blob: 3a2963f8b692d1f5319c20c9cb7a17acbe6d25d0 [file] [log] [blame]
Guido van Rossum70dc86f1994-05-03 14:15:01 +00001# Generator implementation using threads
2
Georg Brandl2067bfd2008-05-25 13:05:15 +00003import _thread as thread
Benjamin Petersond7b03282008-09-13 15:58:53 +00004import sys
Guido van Rossum70dc86f1994-05-03 14:15:01 +00005
Benjamin Petersond7b03282008-09-13 15:58:53 +00006class Killed(Exception):
7 pass
Guido van Rossum70dc86f1994-05-03 14:15:01 +00008
9class Generator:
Tim Peters68a323c2004-07-18 16:56:37 +000010 # Constructor
11 def __init__(self, func, args):
12 self.getlock = thread.allocate_lock()
13 self.putlock = thread.allocate_lock()
14 self.getlock.acquire()
15 self.putlock.acquire()
16 self.func = func
17 self.args = args
18 self.done = 0
19 self.killed = 0
20 thread.start_new_thread(self._start, ())
Benjamin Petersond7b03282008-09-13 15:58:53 +000021
Tim Peters68a323c2004-07-18 16:56:37 +000022 # Internal routine
23 def _start(self):
24 try:
25 self.putlock.acquire()
26 if not self.killed:
27 try:
Neal Norwitzd9108552006-03-17 08:00:19 +000028 self.func(self, *self.args)
Tim Peters68a323c2004-07-18 16:56:37 +000029 except Killed:
30 pass
31 finally:
32 if not self.killed:
33 self.done = 1
34 self.getlock.release()
Benjamin Petersond7b03282008-09-13 15:58:53 +000035
Tim Peters68a323c2004-07-18 16:56:37 +000036 # Called by producer for each value; raise Killed if no more needed
37 def put(self, value):
38 if self.killed:
Collin Winter6f2df4d2007-07-17 20:59:35 +000039 raise TypeError('put() called on killed generator')
Tim Peters68a323c2004-07-18 16:56:37 +000040 self.value = value
41 self.getlock.release() # Resume consumer thread
42 self.putlock.acquire() # Wait for next get() call
43 if self.killed:
44 raise Killed
Benjamin Petersond7b03282008-09-13 15:58:53 +000045
Tim Peters68a323c2004-07-18 16:56:37 +000046 # Called by producer to get next value; raise EOFError if no more
47 def get(self):
48 if self.killed:
Collin Winter6f2df4d2007-07-17 20:59:35 +000049 raise TypeError('get() called on killed generator')
Tim Peters68a323c2004-07-18 16:56:37 +000050 self.putlock.release() # Resume producer thread
51 self.getlock.acquire() # Wait for value to appear
52 if self.done:
53 raise EOFError # Say there are no more values
54 return self.value
Benjamin Petersond7b03282008-09-13 15:58:53 +000055
Tim Peters68a323c2004-07-18 16:56:37 +000056 # Called by consumer if no more values wanted
57 def kill(self):
58 if self.killed:
Collin Winter6f2df4d2007-07-17 20:59:35 +000059 raise TypeError('kill() called on killed generator')
Tim Peters68a323c2004-07-18 16:56:37 +000060 self.killed = 1
61 self.putlock.release()
Benjamin Petersond7b03282008-09-13 15:58:53 +000062
Tim Peters68a323c2004-07-18 16:56:37 +000063 # Clone constructor
64 def clone(self):
65 return Generator(self.func, self.args)
Guido van Rossum70dc86f1994-05-03 14:15:01 +000066
67def pi(g):
Collin Winter6f2df4d2007-07-17 20:59:35 +000068 k, a, b, a1, b1 = 2, 4, 1, 12, 4
Tim Peters68a323c2004-07-18 16:56:37 +000069 while 1:
70 # Next approximation
Collin Winter6f2df4d2007-07-17 20:59:35 +000071 p, q, k = k*k, 2*k+1, k+1
Tim Peters68a323c2004-07-18 16:56:37 +000072 a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
73 # Print common digits
Benjamin Petersond7b03282008-09-13 15:58:53 +000074 d, d1 = a//b, a1//b1
Tim Peters68a323c2004-07-18 16:56:37 +000075 while d == d1:
76 g.put(int(d))
Collin Winter6f2df4d2007-07-17 20:59:35 +000077 a, a1 = 10*(a%b), 10*(a1%b1)
Benjamin Petersond7b03282008-09-13 15:58:53 +000078 d, d1 = a//b, a1//b1
Guido van Rossum70dc86f1994-05-03 14:15:01 +000079
80def test():
Tim Peters68a323c2004-07-18 16:56:37 +000081 g = Generator(pi, ())
82 g.kill()
83 g = Generator(pi, ())
Collin Winter6f2df4d2007-07-17 20:59:35 +000084 for i in range(10): print(g.get(), end=' ')
85 print()
Tim Peters68a323c2004-07-18 16:56:37 +000086 h = g.clone()
87 g.kill()
88 while 1:
Collin Winter6f2df4d2007-07-17 20:59:35 +000089 print(h.get(), end=' ')
Benjamin Petersond7b03282008-09-13 15:58:53 +000090 sys.stdout.flush()
Guido van Rossum70dc86f1994-05-03 14:15:01 +000091
92test()