Way*_*ner 3 python asynchronous tornado
在Tornado的聊天演示中,它有一个这样的方法:
@tornado.web.asynchronous
def post(self):
cursor = self.get_argument("cursor", None)
global_message_buffer.wait_for_messages(self.on_new_messages,
cursor=cursor)
Run Code Online (Sandbox Code Playgroud)
我对这个长时间的轮询很新,我并不完全理解线程的工作原理,尽管它表明:
通过使用非阻塞网络I/O,Tornado可以扩展到数万个开放连接......
我的理论是通过制作一个简单的应用程序:
import tornado.ioloop
import tornado.web
import time
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
print("Start request")
time.sleep(4)
print("Okay done now")
self.write("Howdy howdy howdy")
self.finish()
application = tornado.web.Application([
(r'/', MainHandler),
])
Run Code Online (Sandbox Code Playgroud)
如果我连续发出两个请求(即我打开两个浏览器窗口并快速刷新两个),我会看到:
Start request
Start request
Okay done now
Okay done now
Run Code Online (Sandbox Code Playgroud)
相反,我明白了
Start request
Okay done now
Start request
Okay done now
Run Code Online (Sandbox Code Playgroud)
这让我相信它在这种情况下实际上是阻塞的.为什么我的代码是阻塞的,我如何获得一些代码来做我期望的呢?我在Windows 7上使用核心i7获得相同的输出,并且我认为有两个核心的Linux Mint 13盒子.
我找到了一种方法 - 如果有人能提供一种跨平台工作的方法(我不太担心性能,只是它是非阻塞的),我会接受这个答案.
将测试应用程序转换为不会阻止IOLoop的形式的正确方法是这样的:
from tornado.ioloop import IOLoop
import tornado.web
from tornado import gen
import time
@gen.coroutine
def async_sleep(timeout):
""" Sleep without blocking the IOLoop. """
yield gen.Task(IOLoop.instance().add_timeout, time.time() + timeout)
class MainHandler(tornado.web.RequestHandler):
@gen.coroutine
def get(self):
print("Start request")
yield async_sleep(4)
print("Okay done now")
self.write("Howdy howdy howdy")
self.finish()
if __name__ == "__main__":
application = tornado.web.Application([
(r'/', MainHandler),
])
application.listen(8888)
IOLoop.instance().start()
Run Code Online (Sandbox Code Playgroud)
区别在于将呼叫替换为time.sleep不会阻止IOLoop的呼叫.Tornado旨在处理大量并发I/O而无需多个线程/子进程,但如果使用同步API,它仍会阻塞.为了使您的长轮询解决方案能够按照您的方式处理并发,您必须确保没有长时间运行的调用阻塞.
原始问题中代码的问题在于,当您调用时,time.sleep(4)您实际上阻止了事件循环的执行4秒.并且接受的答案也没有解决问题(恕我直言).
Tornado中的异步服务依赖于信任.Tornado会在发生任何事情时调用您的函数,但它相信您会尽快将控制权返回给它.如果你阻止了time.sleep()这个信任被破坏 - Tornado无法处理新的连接.
使用多个线程只能隐藏错误; 使用数千个线程运行Tornado(因此您可以同时提供1000个连接)将是非常低效的.适当的方法是运行一个单独的线程,它只阻止Tornado内部(select或者Tornado监听事件的方式) - 而不是你的代码(确切地说:永远不会在你的代码上).
正确的解决方案是get(self)从右前方返回time.sleep()(不调用self.finish()),如下所示:
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
print("Starting")
Run Code Online (Sandbox Code Playgroud)
当然,你必须记住,这个要求仍然是开放的,并呼吁write()和finish()以后就可以了.
我建议你看一下聊天演示.删除身份验证后,您将获得一个非常好的异步长轮询服务器示例.
| 归档时间: |
|
| 查看次数: |
4520 次 |
| 最近记录: |