If the use of threads is an option, the generator can be consumed only once, without preserving, possibly, an unpredictable number of received values between calls to consumers. The following example starts users in lock mode; This implementation requires Python 3.2 or later:
import threading
def generator():
for x in range(10):
print('generating {}'.format(x))
yield x
def tee(iterable, n=2):
barrier = threading.Barrier(n)
state = dict(value=None, stop_iteration=False)
def repeat():
while True:
if barrier.wait() == 0:
try:
state.update(value=next(iterable))
except StopIteration:
state.update(stop_iteration=True)
barrier.wait()
if state['stop_iteration']:
break
yield state['value']
return tuple(repeat() for i in range(n))
def func1(iterable):
for x in iterable:
print('func1 consuming {}'.format(x))
def func2(iterable):
for x in iterable:
print('func2 consuming {}'.format(x))
gen1, gen2 = tee(generator(), 2)
thread1 = threading.Thread(target=func1, args=(gen1,))
thread1.start()
thread2 = threading.Thread(target=func2, args=(gen2,))
thread2.start()
thread1.join()
thread2.join()
source
share