thk*_*ang 2 python asynchronous tornado coroutine
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()
Run Code Online (Sandbox Code Playgroud)
上面划出的21条线是简单的因子计算器.它以发电机方式循环N次.
问题是,当这段代码执行时,它会阻止整个龙卷风.
我想要实现的是为龙卷风编写一些帮助器,将生成器视为协程,因此可以异步方式处理请求.(我已经阅读过使用一个简单的python生成器作为Tornado异步处理程序中的一个协同例程?)
为什么简单的增加和乘法循环阻止整个龙卷风?
编辑:我编辑了代码以包含整个应用程序,您可以运行并测试它.我在python 2.7上运行龙卷风3.1.1
你必须记住Tornado在一个线程中运行.代码被拆分为在主循环中顺序调用的任务.如果其中一个任务需要很长时间才能完成(因为像阻塞函数一样time.sleep()或者像factorial 这样的重度计算),它将阻塞整个循环.
那你能做什么......?一种解决方案是使用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()
Run Code Online (Sandbox Code Playgroud)
每次乘法都是一个单独的任务,它允许混合factorial来自不同请求的生成器调用.如果每次调用生成器花费相同的时间,这是一个很好的方法.但是,如果你将计算100000!然后在某个时间点顺序的任务将看起来像90000!*90001,90001!*90002等等.即使它只有一个乘法而不是整个循环,这需要一些时间来计算,因此另一个请求将被延迟.对于这样的大输入整数,您必须在另一个线程中进行计算,以便为请求分配合理的处理器时间.以下是如何执行此操作的示例:http://lbolla.info/blog/2013/01/22/blocking-tornado
作为旁注,在factorial中你有很多冗余,所以你应该保留内存中某些n的解决方案列表,以便立即将它们关闭,而不会一次又一次地浪费处理器时间进行相同的计算.
| 归档时间: |
|
| 查看次数: |
3436 次 |
| 最近记录: |