Python 如何在Tornado中编写非阻塞、分块的RequestHandler
下面是两个简单的Python 如何在Tornado中编写非阻塞、分块的RequestHandler,python,tornado,concurrent.futures,Python,Tornado,Concurrent.futures,下面是两个简单的RequestHandlers: class AsyncHandler(tornado.web.RequestHandler): @gen.coroutine def get(self): while True: future = Future() global_futures.add(future) s = yield future self.writ
RequestHandlers
:
class AsyncHandler(tornado.web.RequestHandler):
@gen.coroutine
def get(self):
while True:
future = Future()
global_futures.add(future)
s = yield future
self.write(s)
self.flush()
class AsyncHandler2(tornado.web.RequestHandler):
@gen.coroutine
def get(self):
for f in global_futures:
f.set_result(str(dt.now()))
global_futures.clear()
self.write("OK")
第一个“订阅”流,第二个向所有订阅者发送消息
问题是我的订户不能超过一堆(在我的例子中是5-6个)。一旦我订阅了超过允许的数量,对第二个方法的下一个请求就会挂起
我假设发生这种情况是因为第一个处理程序没有正确地异步。这是因为我使用全局对象存储订阅者列表吗
我怎样才能同时打开更多的流式处理请求,逻辑限制是什么?问题是,在您对其进行迭代时,
global\u futures
正在被修改:当asynchHandler.get
唤醒时,它会从一个yield
运行到下一个,这意味着它将创建下一个未来,并在控件返回到asynchHandler2
之前将其添加到集合中。这是未定义的,行为取决于迭代器在集合中的位置:有时新的未来被插入到迭代器的“后面”,一切正常,有时它被插入到迭代器的“前面”,同一个使用者处理程序将被第二次唤醒(并插入自身的第三个副本,可能在前面或后面…)。当你只有几个消费者时,你会经常碰到“背后”的情况,这样事情就可以解决了,但如果消费者太多,事情就很难完成
解决方案是在迭代之前复制global\u futures
,而不是在最后清除:
@gen.coroutine
def get(self);
fs = list(global_futures)
global_futures.clear()
for f in fs:
f.set_result(str(dt.now()))
self.write("OK")
请注意,我认为这只是Tornado4.x及更高版本中的一个问题。在Tornado 5中,事情发生了更改,因此set\u result
不再立即调用等待的处理程序,因此不再进行并发修改。谢谢你,Ben,我感谢你的帮助。这个问题与tornado完全无关,它实际上是对浏览器中每个主机并发连接的限制——这个问题与问题的主题无关,这里讨论的是原始问题-