Why is getattr not working? I am not trying to set a default value to threadLocal, I want to know why getattr does not work the way I want it to? tried to lock, same output
Expected Output
0
1
2
3
4
main thread
Current Output
0
0
0
0
0
main thread
Code
from concurrent.futures import ThreadPoolExecutor
from threading import local
threadLocal = local()
threadLocal.x = 'main thread'
def f(x):
# threadLocal.x = x # this works
threadLocal.x = getattr(threadLocal, 'x', x) # this does not work
return threadLocal.x
pool = ThreadPoolExecutor(5)
result = pool.map(f, range(0, 5))
for i in result:
print(i)
print(threadLocal.x)
CodePudding user response:
A Thread pool shares its worker threads between work items. That means that if a work item is finished before the next, both can run on the same thread and thus see the same thread locals.
This is exactly what happens here: since f
is very quick to execute, most or all work items run in the first worker thread. The first task f(0)
sets threadLocal.x = 0
here, and other tasks running in the same thread thus read threadLocal.x = 0
.
You can circumvent this by (artificially) increasing the runtime of f
.
def f(x):
time.sleep(0.2) # delay for other work items to start running
threadLocal.x = getattr(threadLocal, 'x', x) # this works now
return threadLocal.x
Note that any additional operation may be sufficient to break the timing issue: that includes print
ing the argument and thread local, for example.