Python Central HubSign in

Python Programming / Python MultiProcessing

Common Pitfalls (pickling, __main__)

Avoid the most common multiprocessing problems - pickling errors, missing __main__ guard, and oversubscription.

diagram why a multiprocessing script must guard __main__ mermaid
On Windows and macOS a new process is started by launching a fresh interpreter and importing your module. Anything at module level therefore runs again in the child -- including the code that started the process. Without the guard that recursion is unbounded, which is why the symptom is an explosion of processes rather than an error message.

1) Missing main guard

Always use:

Python
if __name__ == "__main__":
    pass

Without this, some environments will repeatedly spawn child processes.

2) Pickling errors

Multiprocessing needs to serialize (pickle) functions and data.

Avoid:

  • lambdas
  • nested functions
  • open file handles
  • database connections

Prefer:

  • top-level functions
  • simple data (numbers/strings/lists/dicts)

3) Oversubscribing CPUs

Creating too many processes can slow down your system.

Guidance:

  • start with os.cpu_count()
  • benchmark for your workloads

4) Returning huge data

Sending massive arrays through Queue can be slow.

Options:

  • write output to files
  • batch results
  • aggregate inside workers
sketch Why a multiprocessing script must guard __main__ p5.js
On Windows and macOS a child process is started by launching a fresh interpreter and IMPORTING your module. So anything at module level runs again in the child -- including the code that started the process. Without the guard that recursion has no bottom, which is why the symptom is an explosion of processes rather than an error.

Why these problems happen

Every pitfall on this page comes from one fact: a child process is a separate program with its own memory. Python cannot hand it your variables directly. It has to serialize (pickle) the function and its arguments, send the bytes across, and rebuild them in the child. On Windows and macOS the child also starts from a fresh interpreter (the spawn start method) that imports your script before doing anything else. Linux historically used fork, which copies the parent and hides several of these bugs, so code that works on Linux may fail on Windows.

A worked example of the guard

Python
from multiprocessing import Process
 
 
def work(n: int) -> None:
    print("child got", n)
 
 
if __name__ == "__main__":
    p = Process(target=work, args=(42,))
    p.start()
    p.join()
    print("parent done")

When the child starts, it imports guard_demo.py. Module-level code runs again, but the if __name__ == "__main__": block does not, because inside the child __name__ is not "__main__". Remove the guard and each child would create another child, which is why the symptom is either a flood of processes or a RuntimeError about bootstrapping.

Fixing a pickling error

Python
from multiprocessing import Pool
 
 
def square(x: int) -> int:  # top-level function: picklable
    return x * x
 
 
if __name__ == "__main__":
    with Pool(2) as pool:
        print(pool.map(square, [1, 2, 3]))
        # pool.map(lambda x: x * x, [1, 2, 3])  # fails: a lambda cannot be pickled

Functions are pickled by name, so they must be importable from the top level of a module. Lambdas and functions defined inside other functions have no importable name.

Common mistakes

  • Leaving out the guard because "it works on my Linux server".
  • Passing open files, sockets or database connections to a worker. Pass a filename or connection settings and open the resource inside the worker.
  • Starting more processes than CPU cores for CPU-bound work. Extra processes only add switching overhead.
  • Sending huge results back through a Queue. Every result is pickled and copied; aggregate in the worker or write to disk.

A quick checklist

Before running multiprocessing code, check that the entry point is guarded, the target is a top-level function, the arguments are plain data, and the pool size is close to os.cpu_count().

Check yourself

quizCheck yourself
  1. Why must `Process(...).start()` sit inside `if __name__ == '__main__':` on Windows?

    Show answer

    B — Because the child starts by importing your module, so module-level start() would recurse — The spawn start method launches a fresh interpreter and imports your module. Anything at module level runs again in the child — including the line that created it.

  2. What is the symptom of forgetting the guard?

    Show answer

    B — An explosion of processes, or a RuntimeError about bootstrapping — The recursion has no bottom, which is why it presents as the machine filling with processes rather than a single clear error at the offending line.

  3. Why can a `lambda` not be passed as a `Process` target on Windows?

    Show answer

    B — Arguments and targets must be PICKLED to reach the child, and a lambda cannot be pickled — Use a module-level function and plain data. The same restriction covers locally defined functions, open files and live connections.

  4. Code using multiprocessing works on Linux and fails on Windows. What is the usual reason?

    Show answer

    A — Windows has no fork, so the default is spawn, which re-imports the module — `fork` copies the process without re-importing, so a missing `__main__` guard is invisible there. The guard costs nothing — write it always.

🧪 Try It Yourself

Exercise 1 – Start a Process

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 2 – Process Pool map()

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 3 – Multiprocessing Queue

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Was this page helpful?

Let us know how we did