Python 如何在同步环境中执行Tornado协程?
我有一些与Tornado的协同程序相关的问题 有一些python模型A,它具有执行某些函数的能力。可以从模型外部设置该功能。我不能改变模型本身,但我可以传递任何我想要的函数。我试图通过我的函数来教它如何使用Tornado的iLoop,但我做不到 以下是片段:Python 如何在同步环境中执行Tornado协程?,python,asynchronous,tornado,future,coroutine,Python,Asynchronous,Tornado,Future,Coroutine,我有一些与Tornado的协同程序相关的问题 有一些python模型A,它具有执行某些函数的能力。可以从模型外部设置该功能。我不能改变模型本身,但我可以传递任何我想要的函数。我试图通过我的函数来教它如何使用Tornado的iLoop,但我做不到 以下是片段: import functools import pprint from tornado import gen from tornado import ioloop class A: f = None def execute
import functools
import pprint
from tornado import gen
from tornado import ioloop
class A:
f = None
def execute(self):
return self.f()
pass
@gen.coroutine
def genlist():
raise gen.Return(range(1, 10))
@gen.coroutine
def some_work():
a = A()
a.f = functools.partial(
ioloop.IOLoop.instance().run_sync,
lambda: genlist())
print "a.f set"
raise gen.Return(a)
@gen.coroutine
def main():
a = yield some_work()
retval = a.execute()
raise gen.Return(retval)
if __name__ == "__main__":
pprint.pprint(ioloop.IOLoop.current().run_sync(main))
所以问题是,我在代码的一部分设置函数,但在另一部分使用模型的方法执行它
现在,Tornado4.2.1给了我“iLoop已经在运行”的信息,但在Tornado3.1.1中它可以工作(但我不知道具体是如何工作的)
我知道接下来的事情:
所以,我的问题是:是否有机会使用当前的IOLoop从同步模型的方法执行异步的
genlist
。您有三种选择:
a.execute()
和堆栈顶部的所有内容更改为协程。这是基于Tornado的应用程序的常见模式;试图跨越同步和异步世界是困难的,最好是站在这一边或那一边IOLoop
上使用run\u sync()
。这就是Tornado的synchronousTornado.httpclient.httpclient
所做的,这使得从另一个IOLoop
中调用变得安全。但是,如果这样做,外部IOLoop仍然被阻塞,因此通过使genlist
异步,您将一无所获a.execute
,并为内部函数调用主IOLoop的线程。如果a.execute
不能设置为异步,这是避免在IOLoop运行时阻塞IOLoop的唯一方法
executor = concurrent.futures.ThreadPoolExecutor(8)
@gen.coroutine
def some_work():
a = A()
def adapter():
# Convert the thread-unsafe tornado.concurrent.Future
# to a thread-safe concurrent.futures.Future.
# Note that everything including chain_future must happen
# on the IOLoop thread.
future = concurrent.futures.Future()
ioloop.IOLoop.instance().add_callback(
lambda: tornado.concurrent.chain_future(
genlist(), future)
return future.result()
a.f = adapter
print "a.f set"
raise gen.Return(a)
@gen.coroutine
def main():
a = yield some_work()
retval = yield executor.submit(a.execute)
raise gen.Return(retval)
比如,您的函数如下所示:
@gen.coroutine
def foo():
# does slow things
或
您可以像这样运行foo()
:
from tornado.ioloop import IOLoop
loop = IOLoop.current()
loop.run_sync(foo)
您可以运行bar(…)
,或任何采用args的协同程序,如下所示:
from functools import partial
from tornado.ioloop import IOLoop
loop = IOLoop.current()
f = partial(bar, i=100)
loop.run_sync(f)
from functools import partial
from tornado.ioloop import IOLoop
loop = IOLoop.current()
f = partial(bar, i=100)
loop.run_sync(f)