fork(1) download
  1. #!/usr/bin/python3
  2.  
  3. import heapq
  4. import time
  5. import types
  6. import logging
  7.  
  8. class EventLoop:
  9. def __init__(self):
  10. self.timers = []
  11. self.seq = 0
  12. def runAfter(self, delay, callback):
  13. self.seq += 1
  14. heapq.heappush(self.timers, (time.time() + delay, self.seq, callback))
  15. def poll(self):
  16. # here we can poll for sockets etc
  17. now = time.time()
  18. while self.timers and now >= self.timers[0][0]:
  19. heapq.heappop(self.timers)[2]()
  20.  
  21. loop = EventLoop()
  22.  
  23. class Future:
  24. def __init__(self):
  25. self.__hasResult = False
  26. self.__result = None
  27. self.__callback = None
  28. def done(self, result):
  29. if self.__callback:
  30. self.__callback(result)
  31. else:
  32. self.__result = result
  33. self.__hasResult = True
  34. def then(self, callback):
  35. if self.__hasResult:
  36. callback(self.__result)
  37. else:
  38. self.__callback = callback
  39. def hasResult(self):
  40. return self.__hasResult
  41.  
  42. class Spawn(Future):
  43. def __init__(self, gen):
  44. super().__init__()
  45. self.gen = gen
  46. self.step(None)
  47. def step(self, arg):
  48. try:
  49. res = self.gen.send(arg)
  50. if isinstance(res, types.GeneratorType):
  51. res = Spawn(res)
  52. res.then(self.step)
  53. except StopIteration as e:
  54. self.done(e.value)
  55.  
  56. class Sleep(Future):
  57. def __init__(self, delay):
  58. super().__init__()
  59. loop.runAfter(delay, lambda: self.done(None))
  60.  
  61. def foo(tid, delay, n):
  62. logging.debug("%d entered foo", tid)
  63. for i in range(0, n):
  64. logging.debug("%d before sleep", tid)
  65. yield Sleep(delay)
  66. logging.debug("%d after sleep", tid)
  67. logging.debug("%d exiting foo", tid)
  68. return n
  69.  
  70. def bar():
  71. logging.debug("entered bar")
  72. f1 = Spawn(foo(1, 0.1, 10))
  73. f2 = Spawn(foo(2, 0.15, 5))
  74. logging.debug("waiting for f1")
  75. r1 = yield f1
  76. logging.debug("f1 result is %d", r1)
  77. logging.debug("waiting for f2")
  78. r2 = yield f2
  79. logging.debug("f1 result is %d", r2)
  80. logging.debug("exiting bar")
  81.  
  82. logging.basicConfig(format="%(asctime)-15s %(message)s", level=logging.DEBUG)
  83.  
  84. s = Spawn(bar())
  85. while not s.hasResult():
  86. loop.poll()
Success #stdin #stdout #stderr 1.04s 10688KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
2016-03-24 21:19:20,142 entered bar
2016-03-24 21:19:20,142 1 entered foo
2016-03-24 21:19:20,142 1 before sleep
2016-03-24 21:19:20,142 2 entered foo
2016-03-24 21:19:20,143 2 before sleep
2016-03-24 21:19:20,143 waiting for f1
2016-03-24 21:19:20,242 1 after sleep
2016-03-24 21:19:20,243 1 before sleep
2016-03-24 21:19:20,293 2 after sleep
2016-03-24 21:19:20,293 2 before sleep
2016-03-24 21:19:20,343 1 after sleep
2016-03-24 21:19:20,343 1 before sleep
2016-03-24 21:19:20,443 1 after sleep
2016-03-24 21:19:20,443 1 before sleep
2016-03-24 21:19:20,443 2 after sleep
2016-03-24 21:19:20,443 2 before sleep
2016-03-24 21:19:20,543 1 after sleep
2016-03-24 21:19:20,543 1 before sleep
2016-03-24 21:19:20,593 2 after sleep
2016-03-24 21:19:20,593 2 before sleep
2016-03-24 21:19:20,643 1 after sleep
2016-03-24 21:19:20,643 1 before sleep
2016-03-24 21:19:20,743 1 after sleep
2016-03-24 21:19:20,744 1 before sleep
2016-03-24 21:19:20,744 2 after sleep
2016-03-24 21:19:20,744 2 before sleep
2016-03-24 21:19:20,844 1 after sleep
2016-03-24 21:19:20,844 1 before sleep
2016-03-24 21:19:20,894 2 after sleep
2016-03-24 21:19:20,894 2 exiting foo
2016-03-24 21:19:20,944 1 after sleep
2016-03-24 21:19:20,944 1 before sleep
2016-03-24 21:19:21,044 1 after sleep
2016-03-24 21:19:21,044 1 before sleep
2016-03-24 21:19:21,144 1 after sleep
2016-03-24 21:19:21,144 1 exiting foo
2016-03-24 21:19:21,144 f1 result is 10
2016-03-24 21:19:21,145 waiting for f2
2016-03-24 21:19:21,145 f1 result is 5
2016-03-24 21:19:21,145 exiting bar