Skip to main content

Python Multicore

A module that makes it easy to parallelize Python code.

Travis

Installation

  1. Install or add multicore to your Python path.

Overview

Python supports multi-threading but the global interpreter lock (GIL) prevents us from utilising all CPU cores for CPU heavy tasks. The recommended approach is to use Python’s multiprocessing library to work around the GIL, but that has its own set of challenges, notably the ability to share data between sub-processes is limited.

The goal of the multicore library is to make it as simple as possible to parallelize code while incurring the least amount of overhead.

Features

  1. Persistent pool of workers enabling persistent database connections.

  2. Memory maps for inter process communication. Much faster than multiprocess’s own IPC or even pipes.

  3. Can take system load average into account to decide whether parallelization is worth it at any given time.

Architecture

Python Multicore is effectively an in-memory queue that is processed by a fixed set of workers. It uses memory mapping to avoid the latency imposed by using a queing system such as celery.

Usage

Let’s render 100 users. Always break a large task into smaller tasks, but not too small! If the ranges are too small then tasks aren’t worth the effort because the overhead becomes too much.:

import time

from multicore import initialize, shutdown, Task
from multicore.utils import ranges


# Note the scoping of the "items" variable and the functions
items = range(100)


def as_string(item):
    return str(item)


def expensive_as_string(item):
    time.sleep(0.01)
    return str(item)


def multi_expensive_as_string(start, end):
    return ",".join([expensive_as_string(item) for item in items[start:end]])


if __name__ == "__main__":

    # Needs to be called only once for lifetime of process
    initialize()

    # Example 1: trivial (and slightly pointless) usage
    task = Task()
    for i in range(20):
        task.run(as_string, i)
    print(", ".join(task.get()))

    # Example 2: divide job optimally using ranges function
    task = Task()
    for start, end in ranges(items):
        # Note we don't pass items because pickling is expensive and defeats
        # the purpose of the exercize.
        task.run(multi_expensive_as_string, start, end)
    print(", ".join(task.get()))

    # Stop the multicore workers
    shutdown()

The Task constructor accepts an optional parameter max_load_average. If the load average for the last minute is larger than a defined threshold then None is returned and your code must cater for the sequential code path. Note that the threshold is specified as for a single core machine, so typically less than one.

The run method accepts an optional parameter serialization_format with value pickle (the default), json or string. Pickle is slow and safe. If you know what type of data you have (you should!) set this as appropriate.

The run method also accepts an optional parameter use_dill with default value False. Dill is a library that can often pickle things that can’t be pickled by the standard pickler but it is slightly slower.

FAQ’s

Will it try to execute hundreds of pieces of code in parallel?

No. The worker pool has a fixed size and can only execute number-of-cores tasks in parallel. You may also set max_load_average as a further guard.

Why didn’t you use multiprocessing.Pool?

It just has too many issues with eg. Django when it comes to scoping. Even pipes and sockets introduce too much overhead, so memory mapping is used.

Do you have any benchmarks?

No, because this is just an interface, not a collection of parallel code.

In general the code scales nearly linearly if you don’t access the database. Multicore itself adds about 5 milliseconds overhead on my machine.

The memory map is too small for my data structures

A future version will address this through dynamic memory map scaling.

Authors

Praekelt Consulting

  • Hedley Roos

Changelog

0.1.1

  1. Update readme with a working example.

  2. Guard against attempting to re-use a completed task.

0.1

  1. Initial release.

Metadata

Release files for multicore 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for multicore 0.1.1
File Size Uploaded Provenance
multicore-0.1.1.tar.gz 23.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for multicore 0.1.1
File Interpreter ABI Platform
multicore-0.1.1-py2.7.egg Legacy Egg format - - Details

Total release size: 38.7 kB

Release files / multicore-0.1.1.tar.gz

Download URL multicore-0.1.1.tar.gz
Size 23.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c45d3f594afcdeb162cc38db2a16567cc82bfad04d346956ea42088fc62b6186
BLAKE2b-256 checksum
How to use checksums
dd08aa2a4f2d602d0c2e32e26fc0e2e7f4e97b0aeda6bf4c7fa74b6aaff9f2fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release files / multicore-0.1.1-py2.7.egg

Download URL multicore-0.1.1-py2.7.egg
Size 15.7 kB
Tags Egg
SHA-256 checksum
How to use checksums
b87846c0ad7881590827041e4a27008f1708a1bdc90650d6eba5d5a5ac70959e
BLAKE2b-256 checksum
How to use checksums
53d9b3c89d9c2c93d367589ff79de3f27c2820b105bcffffe0ce1f68f52ba9c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Security for multicore 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page