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.
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With