/Demo/threads/Generator.py

http://unladen-swallow.googlecode.com/ · Python · 92 lines · 72 code · 11 blank · 9 comment · 15 complexity · f642da2de5b06429fd0cefc9be12a5ee MD5 · raw file

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