假设我有一个耗时很长的函数:
我在处理程序中有一个get函数,它打印出使用xrange中所有数字的for循环的上述结果的用户。
如果我同时在两个Web浏览器上运行以上代码,我会得到:
开始
结束
开始
结束
这似乎是阻塞的。据我理解,
def long_running_function():
result_future = Future()
result = 0
for i in xrange(500000):
result += i
result_future.set_result(result)
return result_future
我在处理程序中有一个get函数,它打印出使用xrange中所有数字的for循环的上述结果的用户。
@gen.coroutine
def get(self):
print "start"
self.future = long_running_function()
message = yield self.future
self.write(str(message))
print "end"
如果我同时在两个Web浏览器上运行以上代码,我会得到:
开始
结束
开始
结束
这似乎是阻塞的。据我理解,
@gen.coroutine
和yield
语句并不会阻塞get函数中的IOLoop,但是,如果协程内部的任何函数是阻塞的,则会阻塞IOLoop。因此,我所做的另一件事情是将long_running_function
转换为回调,并使用yield gen.Task
代替。@gen.coroutine
def get(self):
print "start"
self.future = self.long_running_function
message = yield gen.Task(self.future, None)
self.write(str(message))
print "end"
def long_running_function(self, arguments, callback):
result = 0
for i in xrange(50000000):
result += i
return callback(result)
这不起作用,它会给我:
开始
结束
开始
结束
我可以使用线程并行执行这些操作,但这似乎不是最好的方法,因为我可能会开启很多线程,而根据 Tornado 的用户指南,这可能很昂贵。
人们如何为 Tornado 编写异步库?