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.
--
https://mail.python.org/mailman/listinfo/python-list