我知道generators are not thread safe。当两个线程同时访问时,会发生错误:
ValueError:生成器已在执行
但是迭代器与生成器不同,当在多个线程中使用时,不会引发异常,但会有竞争条件。有关生成器和迭代器之间的比较,请参阅this article。
在那篇文章中,作者使用了一个例子,其中一个计数器同时由两个线程访问,导致其状态'self.i'错误地更新:
class Counter:
def __init__(self):
self.i = 0
def __iter__(self):
return self
def next(self):
self.i += 1
return self.i
这样当线程停止时,self.i将不等于两个线程更新它的次数,但是更小。
但是当迭代器是一个列表迭代器时会有竞争条件吗?例如:
import threading
class Counter(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.num_seen = 0
self.lock = threading.Lock()
def run(self):
global total
for x in idata:
self.num_seen += 1
print('{0} {1}'.format(self.name, self.num_seen))
with self.lock:
total += self.num_seen
count = 10000000
idata = iter([i for i in xrange(count)])
total = 0
nthreads = 5
threads = [Counter() for n in xrange(nthreads)]
for t in threads:
t.start()
for t in threads:
t.join()
print('total ' + str(total))
Everytime total等于count,这是否意味着迭代器是线程安全的?
答案 0 :(得分:0)
我的猜测是,您所看到的内容取决于您正在使用的Python的实现。我假设您正在使用CPython,看起来列表迭代器在CPython中可能是线程安全的。请注意,我没有说他们是线程安全的。您的示例可能仍会触发边缘情况或竞争条件。因此,您不应该依赖于此,因为它不是一个记录的功能,因此它可能会在没有警告的情况下发生变化。
如果需要在多个线程中同时使用迭代器或生成器,则应使用锁或互斥锁来保证线程安全。或者根据@ 9000的建议,使用deque来记录支持“线程安全...附加和弹出”。