问题描述
from tornado import web, gen
import tornado, time
class CoroutineFactorialHandler(web.RequestHandler):
@web.asynchronous
@gen.coroutine
def get(self, n, *args, **kwargs):
n = int(n)
def callbacker(iterator, callback):
try:
value = next(iterator)
except StopIteration:
value = StopIteration
callback(value)
def factorial(n):
x = 1
for i in range(1, n+1):
x *= i
yield
yield x
iterator = factorial(n)
t = time.time()
self.set_header("Content-Type", "text/plain")
while True:
response = yield gen.Task(callbacker, iterator)
#log.debug("response: %r" %response)
if response is StopIteration:
break
elif response:
self.write("took : %f sec" %(time.time() - t))
self.write("\n")
self.write("f(%d) = %d" %(n, response))
self.finish()
application = tornado.web.Application([
(r"^/coroutine/factorial/(?P<n>\d+)", CoroutineFactorialHandler),
#http://localhost:8888/coroutine/factorial/<int:n>
])
if __name__ == "__main__":
application.listen(8888)
ioloop = tornado.ioloop.IOLoop.instance()
ioloop.start()
21行猛拉
以上就是简单的阶乘计算器。它循环N次,在发电机的方式。
21 lines yankedabove is the simple factorial calculator. it loops N times, in generator fashion.
问题是,当这种code正在执行它阻止了整个龙卷风。
the problem is, when this code is executing it blocks the whole tornado.
我要实现的是写龙卷风了一些辅助的治疗发生器作为协程,因此可以服务于异步方式的要求是什么。
(我已阅读<一个href=\"http://stackoverflow.com/questions/8812715/using-a-simple-python-generator-as-a-co-routine-in-a-tornado-async-handler?rq=1\">Using一个简单的Python发生器作为龙卷风异步处理程序协同例程?)
what I want to achieve is writing some helper for tornado that treats generators as coroutine, and therefore can serve requests in asynchronous manner.(I have read Using a simple python generator as a co-routine in a Tornado async handler?)
为什么简单的增加和乘乘n循环块,整个龙卷风?
why does the simple increase-and-multiply-by-n loop block the whole tornado?
编辑:我编辑了code到包括整个应用程序,您可以运行并测试它。
我在Python 2.7版运行龙卷风3.1.1
edit : I edited the code to include the whole application, that you can run and test it.I'm running tornado 3.1.1 on python 2.7
推荐答案
您必须记住,龙卷风在一个线程中运行。的code被分成任务被调用顺序中主循环。如果这些任务之一,需要很长的完成(因为阻塞功能,如 time.sleep的()
或一些繁重的计算阶乘一样),它会阻止整个循环结果。
You have to remember that Tornado runs in one thread. The code is split into task that are called sequentially in main loop. If one of these task takes long to finish (because of blocking functions like time.sleep()
or some heavy computation like factorial) it will block entire loop as a result.
所以,你可以做什么......?一种解决方案是使用创建循环 IOLoop.add_callback()
:
So what you can do...? One solution is to create loop using IOLoop.add_callback()
:
from tornado import web, gen
import tornado, time
class CoroutineFactorialHandler(web.RequestHandler):
def factorial(self, limit=1):
count = 1
fact = 1
while count <= limit:
yield fact
count = count + 1
fact = fact * count
def loop(self):
try:
self.fact = self.generator.next()
tornado.ioloop.IOLoop.instance().add_callback(self.loop)
except StopIteration:
self.write("took : %f sec" %(time.time() - self.t))
self.write("\n")
self.write("f(%d) = %d" % (self.n, self.fact))
self.finish()
@web.asynchronous
def get(self, n, *args, **kwargs):
self.n = int(n)
self.generator = self.factorial(self.n)
self.t = time.time()
self.set_header("Content-Type", "text/plain")
tornado.ioloop.IOLoop.instance().add_callback(self.loop)
application = tornado.web.Application([
(r"^/coroutine/factorial/(?P<n>\d+)", CoroutineFactorialHandler),
#http://localhost:8888/coroutine/factorial/<int:n>
])
if __name__ == "__main__":
application.listen(8888)
ioloop = tornado.ioloop.IOLoop.instance()
ioloop.start()
每一个乘法是这里一个单独的任务,它允许混合阶乘
生成不同的请求调用。这是一个很好的方法,如果要生成每次调用了时间相同。但是,如果你将被计算100000!然后在序列时间任务的一些点将看起来像90000!* 90001,90001!* 90002等。它需要一定的时间,以具有此计算,即使其仅一次乘法,而不是整个循环因此其他请求将被延迟。对于这样大的输入整数,你不得不在另一个线程的计算有处理器时间公平份额的请求。我这里是如何做到这一点:http://lbolla.info/blog/2013/01/22/blocking-tornado
Every multiplication is a separate task here, which allows mixing factorial
generator calls from different requests. This is a good approach if every call to generator took same amount of time. However if you will be computing 100000! then at some point in time tasks in sequence will be looking like 90000!*90001, 90001!*90002 and so on. It takes some time to have this computed even if its only one multiplication instead of whole loop so the other request will be delayed. For such big input integer you have to make computations in another thread to have fair share of processor time for a request. Here is example how to do this: http://lbolla.info/blog/2013/01/22/blocking-tornado
作为一个方面说明,在阶乘你有很多冗余的,所以你应该在内存中的保留解决方案列表对于某个n把他们实时的而不是一遍一遍浪费处理器时间相同的计算。
As a side note, in factorial you have a lot of redundancy so you should keep list of solutions for some n at memory to turn them back instantly without wasting processor time for same computation over and over again.
这篇关于为什么我的协同程序块整个龙卷风实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!