3

Code:

import gevent
import time

def func(a, t):
  time.sleep(t)
  print "got here", a

gevent.spawn(func, 'a', 4)
gevent.spawn(func, 'b', 0).join()
time.sleep(3)
print "exit"

Output:

got here a
got here b
exit

Expectation:

I never join on the first greenlet, so I expect that it will never execute; or, given the long sleep(), it should complete after the second greenlet.

Context:

I would like to be able to fire off a "throwaway" greenlet that populates a cache which I never join on and I never want to block to wait for the result of.

ʞɔıu
  • 47,148
  • 35
  • 106
  • 149

1 Answers1

5

This is because time.sleep() isn't gevent-aware, so when join() is called, the execution flow will be:

  1. gevent.spawn(a) — pushes a "spawn a" operation onto the event queue
  2. gevent.spawn(b) — pushes a "spawn b" operation onto the event queue
  3. .join() — causes the main thread to yield and next event in the event queue is executed (in this case, a)
  4. a executes time.sleep(4), blocking the entire process for 4 seconds (but thread a doesn't yield because time.sleep() isn't gevent-aware)
  5. a terminates and the next event in the event queue is executed (in this case, b)
  6. b executes and terminates, and the next event on the queue is executed (in this case, jumping back into the main thread, causing the .join() to return)

Use either gevent.monkey or gevent.sleep() to see this perform as you'd expect.

David Wolever
  • 148,955
  • 89
  • 346
  • 502
  • Why does it execute at all if I never join on it? – ʞɔıu Mar 01 '13 at 18:12
  • I've updated my answer to clarify a bit what's going on behind the scenes… Does that help? – David Wolever Mar 01 '13 at 20:42
  • so gevent has a global event queue, and calling join() on a single greenlet actually starts everything in the queue? – ʞɔıu Mar 01 '13 at 23:53
  • Uuhh… Sort of, yes! Calling join pushes an event onto the end of the queue which is "resume once has completed", then yields (nb: there may be some optimizations there if the thread has already completed… but that's the general idea). – David Wolever Mar 02 '13 at 00:18
  • In general, blocking operations in gevent are handled by pushing an event onto the queue and then yielding. At least, that's a reasonable mental model. – David Wolever Mar 02 '13 at 03:56