I have the following Python code:
>>> import gevent
>>> from gevent import monkey; monkey.patch_all()
>>>
>>> def fooFn(k):
... return 'gevent_'+k
...
>>> threads = []
>>> threads.append(gevent.spawn(fooFn,'0'))
>>> threads.append(gevent.spawn(fooFn,'1'))
>>>
>>> gevent.joinall([threads[1]])
>>>
>>> print threads[1].value
gevent_1
>>> print threads[0].value
gevent_0
>>>
As seen above, threads[0].value
got a proper value from the fooFn
. This means that the threads[0]
greenlet was executed.
Why did this this happen when I passed only the threads[1]
greenlet to gevent.joinall
?
How can I make sure that only those greenlets are executed which are actually passed to gevent.joinall
?
Your greenlets are scheduled immediately when you call greenlet.spawn()
. In other words, they are created and started at once when you call spawn()
. That's why the first greenlet is finished running - both greenlets were executing from the moment you spawned them, and by the time you got around to looking up the results from greenlet 1, both were done executing.
gevent.joinall()
doesn't execute greenlets - it only tells the main thread (the one that actually spawn
ed them) to wait for the ones passed in as parameters to finish running. Not calling joinall
runs the risk of the main thread finishing and exiting before the results of the greenlets in joinall()
has been reached, and then who's going to handle their results?
Here, you did two things that you should change in order to see gevents
behave like you want:
You called joinall()
in the console REPL, rather than from a script.
Here, the main thread - the REPL - is guaranteed to not finish before the
greenlets return, because the REPL only ends when you call exit()
or indicate EOF. In a script with no immediate user interaction, however, you don't have that luxury - execution ends when there's nothing left in the script to do. That's why we call join()
to ensure that the main thread never exits and leaves your greenlet hanging with no parent to return to.
There's no point in calling joinall()
in the console (although if you want a guarantee you'll have results from the greenlet when you next call a function on the greenlet, it's a good idea)
You shouldn't have called spawn()
if you want to guarantee only greenlet 1 is executed while greenlet 2 isn't. Instead, read what the docs say:
To start a new greenlet, pass the target function and its arguments to Greenlet constructor and call start():
>>> g = Greenlet(myfunction, 'arg1', 'arg2', kwarg1=1)
>>> g.start()
or use classmethod
spawn()
which is a shortcut that does the same:
>>> g = Greenlet.spawn(myfunction, 'arg1', 'arg2', kwarg1=1)
Using start
to indicate the greenlet should start running at this moment is a good idea. So: create two greenlet objects, and only call start
on one of them to have only that one execute.