|
1600
|
1 # Generator implementation using threads
|
|
|
2
|
|
|
3 import thread
|
|
|
4
|
|
|
5 Killed = 'Generator.Killed'
|
|
|
6
|
|
|
7 class Generator:
|
|
|
8 # Constructor
|
|
|
9 def __init__(self, func, args):
|
|
|
10 self.getlock = thread.allocate_lock()
|
|
|
11 self.putlock = thread.allocate_lock()
|
|
|
12 self.getlock.acquire()
|
|
|
13 self.putlock.acquire()
|
|
|
14 self.func = func
|
|
|
15 self.args = args
|
|
|
16 self.done = 0
|
|
|
17 self.killed = 0
|
|
|
18 thread.start_new_thread(self._start, ())
|
|
|
19 # Internal routine
|
|
|
20 def _start(self):
|
|
|
21 try:
|
|
|
22 self.putlock.acquire()
|
|
|
23 if not self.killed:
|
|
|
24 try:
|
|
|
25 apply(self.func, (self,) + self.args)
|
|
|
26 except Killed:
|
|
|
27 pass
|
|
|
28 finally:
|
|
|
29 if not self.killed:
|
|
|
30 self.done = 1
|
|
|
31 self.getlock.release()
|
|
|
32 # Called by producer for each value; raise Killed if no more needed
|
|
|
33 def put(self, value):
|
|
|
34 if self.killed:
|
|
|
35 raise TypeError, 'put() called on killed generator'
|
|
|
36 self.value = value
|
|
|
37 self.getlock.release() # Resume consumer thread
|
|
|
38 self.putlock.acquire() # Wait for next get() call
|
|
|
39 if self.killed:
|
|
|
40 raise Killed
|
|
|
41 # Called by producer to get next value; raise EOFError if no more
|
|
|
42 def get(self):
|
|
|
43 if self.killed:
|
|
|
44 raise TypeError, 'get() called on killed generator'
|
|
|
45 self.putlock.release() # Resume producer thread
|
|
|
46 self.getlock.acquire() # Wait for value to appear
|
|
|
47 if self.done:
|
|
|
48 raise EOFError # Say there are no more values
|
|
|
49 return self.value
|
|
|
50 # Called by consumer if no more values wanted
|
|
|
51 def kill(self):
|
|
|
52 if self.killed:
|
|
|
53 raise TypeError, 'kill() called on killed generator'
|
|
|
54 self.killed = 1
|
|
|
55 self.putlock.release()
|
|
|
56 # Clone constructor
|
|
|
57 def clone(self):
|
|
|
58 return Generator(self.func, self.args)
|
|
|
59
|
|
|
60 def pi(g):
|
|
|
61 k, a, b, a1, b1 = 2L, 4L, 1L, 12L, 4L
|
|
|
62 while 1:
|
|
|
63 # Next approximation
|
|
|
64 p, q, k = k*k, 2L*k+1L, k+1L
|
|
|
65 a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
|
|
|
66 # Print common digits
|
|
|
67 d, d1 = a/b, a1/b1
|
|
|
68 while d == d1:
|
|
|
69 g.put(int(d))
|
|
|
70 a, a1 = 10L*(a%b), 10L*(a1%b1)
|
|
|
71 d, d1 = a/b, a1/b1
|
|
|
72
|
|
|
73 def test():
|
|
|
74 g = Generator(pi, ())
|
|
|
75 g.kill()
|
|
|
76 g = Generator(pi, ())
|
|
|
77 for i in range(10): print g.get(),
|
|
|
78 print
|
|
|
79 h = g.clone()
|
|
|
80 g.kill()
|
|
|
81 while 1:
|
|
|
82 print h.get(),
|
|
|
83
|
|
|
84 test()
|