I am trying to convert a fairly simple gevent code to use the asynchronous features of Tornado. The sample code below uses the ZMQ library to perform a very simple request-response.
import zmq.green as zmq
def fun():
i = zmq.Context.instance()
sock = i.socket(zmq.REQ)
sock.connect('tcp://localhost:9005')
sock.send('Ping')
return sock.recv()
I can run it like fun()anywhere in my code. Locks are .recv()blocked while waiting for a response, and the hub geventcan schedule other parts of the code. When the values โโare received, the function returns the value.
I read the problems that may occur with these implicit incomes and I want to run it using Tornado IOLoop (also because I want to run it in IPython Notebook). Below is the option where recv_future()returns Futurewhich contains the result:
@gen.coroutine
def fun():
i = zmq.Context.instance()
sock = i.socket(zmq.REQ)
sock.connect('tcp://localhost:9005')
sock.send('Ping')
msg = yield recv_future(sock)
print "Received {}".format(msg[0])
raise gen.Return(msg)
def recv_future(socket):
zmqstream = ZMQStream(socket)
future = Future()
def _finish(reply):
future.set_result(reply)
zmqstream.on_recv(_finish)
return future
The problem is that now fun()it is not a function, but a generator. Therefore, if I need to call it from another function, I need to use yield fun(). But then the calling function also becomes a generator!
What is the right way to structure code that uses Python generators? Do I have to make each function a generator in order for it to work? What if I need to call one of these functions from __init__()? Should it become a generator?