I know that generators are not thread safe. When accessed by two threads at the same time, an error occurs:
ValueError: generator already executing
But iterators are different from generators, when used in a multiple threads, no exception is raised, but there will be race conditions. See this article for the comparision between generators and iterators.
In that articles, the author uses an example where a Counter is accessed by two threads at the same time, causing its state 'self.i' incorrectly updated:
class Counter:
def __init__(self):
self.i = 0
def __iter__(self):
return self
def next(self):
self.i += 1
return self.i
so that when the threads stop, self.i will not equal the number of times it is updated by the two threads, but is smaller.
But will there be race conditions when the iterator is a list iterator? For example:
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 equals count, does this mean the iterator is thread safe?