I'm trying coroutines pipeline according to http://www.dabeaz.com/coroutines/Coroutines.pdf
The question is, how can I get value from the sink
rather than only print it?
Take this code for example
def coroutine(func):
def start(*args, **kwargs):
cr = func(*args, **kwargs)
next(cr)
return cr
return start
@coroutine
def produce(target):
while True:
n = (yield)
target.send(n*10)
@coroutine
def sink():
try:
while True:
n = (yield)
print(n)
except GeneratorExit:
pass
sk = sink()
pipe = produce(sink())
With this code I get:
>>> pipe.send(10)
100
Then I want to get the return value rather than print it, I try to yield from sink:
@coroutine
def sink():
try:
while True:
yield (yield)
except GeneratorExit:
pass
But it seems not working, pipe.send(10)
still returns None
rather than a generator.
So how shall I get the return value?
How can I capture that value and return it when calling the method? You would need to make searchTeamEvents() a suspend function and reorganize your code to take advantage of that, so you can get rid of launch() from searchTeamEvents() and move it into whatever calls searchTeamEvents() .
Coroutines work cooperatively multitask by suspending and resuming at set points by the programmer. In Python, coroutines are similar to generators but with few extra methods and slight changes in how we use yield statements. Generators produce data for iteration while coroutines can also consume data.
Creating TasksWrap the coro coroutine into a Task and schedule its execution. Return the Task object. If name is not None , it is set as the name of the task using Task.set_name() . The task is executed in the loop returned by get_running_loop() , RuntimeError is raised if there is no running loop in current thread.
Coroutines and generators are very different concepts. Generators let you create functions that look like iterators to the consumer. Coroutines are an extension of the concept of traditional functions. A function will hand control back to its caller once through the return statement.
Why should pipe.send
return a generator? And what are you going to do with the returned value?
Whatever it is, it should be done in sink
.
You could, however, change your functions to
@coroutine
def produce(target):
while True:
n = (yield)
yield target.send(n*10)
@coroutine
def sink():
try:
while True:
yield (yield)
except GeneratorExit:
pass
to yield the value yielded by target
, so pipe.send(10)
will just return 100
instead of printing it.
But now you mix the producer and the consumer, which will potentially give you some headache.
In response to your comment:
from collections import defaultdict
def coroutine(func):
def start(*args, **kwargs):
cr = func(*args, **kwargs)
next(cr)
return cr
return start
@coroutine
def produce(key, target):
while True:
n = (yield)
target.send((key, n*10))
class Sink(object):
def __init__(self):
self.d = defaultdict(lambda: None)
self.co = self.sink()
def send(self, *args):
self.co.send(*args)
@coroutine
def sink(self):
try:
while True:
key, n = yield
self.d[key] = max(self.d[key], n)
except GeneratorExit:
pass
sk = Sink()
pipeA = produce("A", sk)
pipeB = produce("B", sk)
pipeA.send(10)
pipeA.send(20)
pipeA.send(40)
pipeB.send(20)
pipeB.send(40)
pipeB.send(60)
print sk.d.items() # [('A', 400), ('B', 600)]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With