Python gevent至Tornado ioloop-带协同程序/生成器的结构代码
我正在尝试转换一些相当简单的gevent代码,以使用Tornado的异步功能。下面的示例代码使用ZMQ库执行非常简单的请求-响应Python gevent至Tornado ioloop-带协同程序/生成器的结构代码,python,asynchronous,tornado,gevent,Python,Asynchronous,Tornado,Gevent,我正在尝试转换一些相当简单的gevent代码,以使用Tornado的异步功能。下面的示例代码使用ZMQ库执行非常简单的请求-响应 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() 我可
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()
我可以在我的代码中的任何地方将其作为fun()
运行。.recv()
调用在等待应答时阻塞,而gevent
中心可以安排代码的其他部分。当收到值时,函数返回值
我读了,我想用Tornado iLoop运行它(也是因为我想在IPython笔记本中运行它)。以下是一个选项,其中recv\u future()
返回一个包含结果的future
:
@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) # Required for ZMQ
future = Future()
def _finish(reply):
future.set_result(reply)
zmqstream.on_recv(_finish)
return future
问题是现在fun()
不是一个函数,而是一个生成器。因此,如果我需要从另一个函数调用它,我需要使用yield fun()
。但是调用函数也变成了生成器
使用Python生成器构造代码的正确方法是什么?我是否必须使每个函数都成为一个生成器才能使其工作?如果我需要从\uuuu init\uuuu()
调用其中一个函数,该怎么办?这也应该成为一个发电机吗
如果我需要从\uuuu init\uuuu()
调用其中一个函数,该怎么办?应该
那也会变成发电机吗
这是使用yield
/yield from
(在Python 3.3+上)的显式异步编程目前尚未解决的问题之一。魔法方法不支持它们。您可以阅读Python核心开发人员关于异步编程的一些有趣想法,这些想法涉及到这个问题
使用Python生成器构造代码的正确方法是什么?
我是否必须使每个函数都成为一个生成器才能使其工作?
不是每个函数,而是要调用协同路由的每个函数,并等待该协同路由完成后再继续。当您切换到一个显式异步编程模型时,您通常希望完全使用它——您的整个程序都在tornado ioloop中运行。因此,在这个玩具示例中,您只需执行以下操作:
看起来您可以通过以下方式访问ioloop IPython正在使用的iLoop:
[4]中的:来自IPython.kernel.ioloop导入管理器
[5]中:manager.ioloop.ioloop.instance()
出[5]:
from tornado.ioloop import IOLoop
from tornado.gen import coroutine
from tornado.concurrent import Future
@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) # Required for ZMQ
future = Future()
def _finish(reply):
future.set_result(reply)
zmqstream.on_recv(_finish)
return future
if __name__ == "__main__":
ioloop = IOLoop.instance()
ioloop.add_callback(fun)
ioloop.start() # This will run fun, and then block forever.
#ioloop.run_sync(fun) # This will start the ioloop, run fun, then stop the ioloop
In [4]: from IPython.kernel.ioloop import manager
In [5]: manager.ioloop.IOLoop.instance()
Out[5]: <zmq.eventloop.ioloop.ZMQIOLoop at 0x4249ac8>