Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python's multiprocessing Does Not Play Nicely With threading.local?

I have two processes (see sample code) that each attempt to access a threading.local object. I would expect the below code to print "a" and "b" (in either order). Instead, I get "a" and "a". How can I elegantly and robustly reset the threading.local object when I startup whole new processes?

import threading
import multiprocessing
l = threading.local()
l.x = 'a'
def f():
    print getattr(l, 'x', 'b')
multiprocessing.Process(target=f).start()
f()

edit: For reference, when I use threading.Thread instead of multiprocessing.Process, it works as expected.

like image 452
dave mankoff Avatar asked Sep 02 '11 15:09

dave mankoff


People also ask

Why Python is not good for multithreading?

Python doesn't support multi-threading because Python on the Cpython interpreter does not support true multi-core execution via multithreading. However, Python does have a threading library. The GIL does not prevent threading.

Can you use threading and multiprocessing?

Both multithreading and multiprocessing allow Python code to run concurrently. Only multiprocessing will allow your code to be truly parallel. However, if your code is IO-heavy (like HTTP requests), then multithreading will still probably speed up your code.

What are the limitations of threading in Python?

In fact, a Python process cannot run threads in parallel but it can run them concurrently through context switching during I/O bound operations. This limitation is actually enforced by GIL. The Python Global Interpreter Lock (GIL) prevents threads within the same process to be executed at the same time.

Is multiprocessing better than threading?

If your program is IO-bound, both multithreading and multiprocessing in Python will work smoothly. However, If the code is CPU-bound and your machine has multiple cores, multiprocessing would be a better choice.


1 Answers

There is now a multiprocessing-utils (github) library on pypi with a multiprocessing-safe version of threading.local() which can be pip installed.

It works by wrapping a standard threading.local() and checking that the PID has not changed since it was last used (as per the answer here from @immortal).

Use it exactly like threading.local():

l = multiprocessing_utils.local()
l.x = 'a'
def f():
    print getattr(l, 'x', 'b')
f()                                        # prints "a"
threading.Thread(target=f).start()         # prints "b"
multiprocessing.Process(target=f).start()  # prints "b"

Full disclosure: I just created this module

like image 118
Jamie Cockburn Avatar answered Oct 20 '22 00:10

Jamie Cockburn