import threading
class Foo(object):
instance_count = 0
def inc_by(n):
for i in xrange(n):
Foo.instance_count += 1
threads = [threading.Thread(target=inc_by, args=(100000,)) for thread_nr in xrange(100)]
for thread in threads: thread.start()
for thread in threads: thread.join()
print(Foo.instance_count) # Expected 10M for threadsafe ops, I get around 5M
Foo.lock = threading.Lock()
def interlocked_inc(n):
for i in xrange(n):
with Foo.lock:
Foo.instance_count += 1
threads = [threading.Thread(target=interlocked_inc, args=(100000,)) for thread_nr in xrange(100)]
for thread in threads: thread.start()
for thread in threads: thread.join()
print(Foo.instance_count)
def threadsafe_function(fn):
"""decorator making sure that the decorated function is thread safe"""
lock = threading.Lock()
def new(*args, **kwargs):
lock.acquire()
try:
r = fn(*args, **kwargs)
except Exception as e:
raise e
finally:
lock.release()
return r
return new
class X:
var = 0
@threadsafe_function
def inc_var(self):
X.var += 1
return X.var
即使在CPython上也不安全。你自己试试看:
原因是,虽然INPLACE_ADD在GIL下是原子的,但属性仍然被加载和存储(请参见dis.dis(Foo.u init_u))。使用锁序列化对类变量的访问:
不,这不是线程安全的。几天前我也遇到过类似的问题,幸亏有一个装饰器,我才选择实现锁。这样做的好处是使代码可读:
我认为它是线程安全的,至少在CPython实现上是这样。GIL将使您的所有“线程”按顺序运行,这样它们就不会干扰您的引用计数。
相关问题 更多 >
编程相关推荐