Trying to use threading.local()

MRAB python at mrabarnett.plus.com
Wed Sep 12 15:44:36 EDT 2018


On 2018-09-12 17:16, Steven D'Aprano wrote:
> I'm originally posted this on the Python-Ideas list, but this is probably
> more appropriate.
> 
> 
> import time
> from threading import Thread, local
> 
> def func():
>      pass
> 
> def attach(value):
>      func.__params__ = local()
>      func.__params__.value = value
> 
> 
> def worker(i):
>      print("called from thread %s" % i)
>      attach(i)
>      assert func.__params__.value == i
>      time.sleep(3)
>      value = func.__params__.value
>      if value != i:
>          print("mismatch", i, value)
> 
> for i in range(5):
>      t = Thread(target=worker, args=(i,))
>      t.start()
> 
> print()
> 
> 
> 
> 
> 
> When I run that, each of the threads print their "called from ..."
> message, the assertions all pass, then a couple of seconds later they
> consistently all raise exceptions:
> 
> Exception in thread Thread-1:
> Traceback (most recent call last):
>    File "/usr/local/lib/python3.5/threading.py", line 914, in
> _bootstrap_inner
>      self.run()
>    File "/usr/local/lib/python3.5/threading.py", line 862, in run
>      self._target(*self._args, **self._kwargs)
>    File "<stdin>", line 5, in worker
> AttributeError: '_thread._local' object has no attribute 'value'
> 
> 
> 
> What am I doing wrong?
> 
I've changed the code to:

import time
from threading import Thread, local

def func():
     pass

def attach(value):
     func.__params__ = local()
     func.__params__.value = value

def worker(i):
     print("called from thread %s" % i)
     attach(i)
     print('thread %s before sleep => %s' % (i, func.__params__))
     assert func.__params__.value == i
     time.sleep(1)
     print('thread %s after sleep => %s' % (i, func.__params__))
     time.sleep(1)
     print('thread %s finally => %s' % (i, func.__params__))
     print('stored value for thread %s is %s' % (i, 
getattr(func.__params__, 'value', 'MISSING')))

for i in range(2):
     t = Thread(target=worker, args=(i,))
     t.start()

print()



My output is:

called from thread 0
thread 0 before sleep => <_thread._local object at 0x0000014936FB8C50>
called from thread 1
thread 1 before sleep => <_thread._local object at 0x0000014936FB8CA8>

thread 1 after sleep => <_thread._local object at 0x0000014936FB8CA8>
thread 0 after sleep => <_thread._local object at 0x0000014936FB8CA8>
thread 0 finally => <_thread._local object at 0x0000014936FB8CA8>
stored value for thread 0 is MISSING
thread 1 finally => <_thread._local object at 0x0000014936FB8CA8>
stored value for thread 1 is 1


Note that thread 1 is overwriting the reference to the thread-local 
storage of thread 0.

It looks like what's happening is that thread 0 ends up trying to read 
the storage for thread 1, but as it's for a different thread, the 
contents aren't visible to it.



More information about the Python-list mailing list