Reputation: 315
I was implementing greenlet API just for practicing.
from greenlet import greenlet
def test1():
print 12
gr2.switch()
print 34
def test2():
print 56
gr1.switch()
print 78
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
here's my messy code
def test1():
tmp1=yield
print 12
try:
gv2.send(1)
except StopIteration:
pass
tmp1=yield
print 34
def test2():
tmp2=yield
print 56
try:
gv2.send(1)
except StopIteration:
pass
tmp1=yield
print 78
gv1=test1()
gv1.next()
gv2=test2()
gv2.next()
gv1.send(1)
Shows,
12
56
Traceback (most recent call last):
File "prog.py", line 26, in <module>
gv1.send(1)
File "prog.py", line 5, in test1
gv2.send(1)
File "prog.py", line 15, in test2
gv2.send(1)
ValueError: generator already executing
So, I don't know I guess correctly,
but It looks that after test1 send '1' to test2, it still has something,
no control-flow switching happens unlike gevent. test1 still have the flow.
if not, I don't understand what greenlet can do but python "coroutine" can't exists.
My question is
Upvotes: 3
Views: 947
Reputation: 16905
The generator instance of test2()
is sending a value to itself.
def test2():
tmp2=yield
print 56
try:
gv2.send(1) # this is the offending line
except StopIteration:
pass
tmp1=yield
print 78
send()
will resume the generator, but whenever code is executed inside test2()
, it is already running. That is why it throws up.
Did you want to do: gv1.send(1)
? That would not work either.
Here is why:
gv1.send(1)
at the very end of your example
gv1.send(1)
is invoked, this resumes gv1
gv1
proceeds to gv2.send(1)
gv2
gv2
proceeds to gv1.send(1)
gv1
is being resumed, however, gv1
has not reached a yield
statement since it was last resumed. Ergo, it is still running, which is why it would also throw.Essentially, the difference could be summarized like this:
.switch()
pauses the currently executing greenlet and will resume however.yield
will "pause" a generatornext()
/ send()
will resume a paused generator, invoking them on running generators will result in an exception.Why are you accessing gv2
(which represents one particular instance of test2
) at all? The generator test2()
should be self-contained and not make any assumptions about how it is being used. What if you decide, that you want to invoke the generator from some other scope? It doesn't make any sense to send values to yourself anyway: You already have them.
Upvotes: 7