使用Tornado设计异步请求和阻塞处理

时间:2016-01-12 13:33:49

标签: python multithreading tornado

我正在尝试使用基于Tornado的NATS来使用client来使用异步函数来接收和发送消息。一旦收到消息,就必须调用一个阻塞函数,我试图在一个单独的线程上实现,以允许接收和发布消息,将消息放入Tornado队列,以便以后处理阻塞函数。

我对Tornado(以及python多线程)非常陌生,但在多次阅读Tornado文档和其他资源后,我已经能够提供代码的工作版本,如下所示: / p>

import tornado.gen
import tornado.ioloop
from tornado.queues import Queue
from concurrent.futures import ThreadPoolExecutor
from nats.io.client import Client as NATS

messageQueue = Queue()
nc = NATS()
@tornado.gen.coroutine
def consumer():
    def processMessage(currentMessage):
        # process the message ...

    while True:
        currentMessage = yield messageQueue.get()
        try:
            # execute the call in a separate thread to prevent blocking the queue
            EXECUTOR.submit(processMessage, currentMessage)
        finally:
            messageQueue.task_done()

@tornado.gen.coroutine
def producer():
    @tornado.gen.coroutine
    def enqueueMessage(currentMessage):
        yield messageQueue.put(currentMessage)

    yield nc.subscribe("new_event", "", enqueueMessage)

@tornado.gen.coroutine
def main():
    tornado.ioloop.IOLoop.current().spawn_callback(consumer)
    yield producer()

if __name__ == '__main__':
    main()
    tornado.ioloop.IOLoop.current().start()

我的问题是:

1)这是使用Tornado调用阻塞函数的正确方法吗?

2)实施始终聆听的消费者/生产者计划的最佳做法是什么?我担心我的while True:声明实际上阻止了处理器......

3)我如何检查队列以确保一连串的呼叫被排队?我尝试过使用Queue()。qSize(),但它总是返回零,这让我想知道排队是否正确完成。

1 个答案:

答案 0 :(得分:1)

一般规则(NYKevin的信用)是:

  • 用于CPU和GPU绑定计算的多处理。
  • 用于非阻塞I / O的事件驱动的东西(在可能的情况下应优先于阻塞I / O,因为它可以更有效地扩展)。
  • 用于阻止I / O的线程(您也可以使用多处理,但每个进程的开销可能不值得)。

IO的ThreadPoolExecutor,CPU的ProcessPoolExecutor。两者都有内部队列,两者都扩展为最多指定的max_workers。有关concurrent executors in docs的更多信息。

答案是:

  1. 重新实现池是一种开销。线程或流程取决于您打算做什么。
  2. while True如果您有例如有些人产生了异步调用(偶数yield gen.sleep(0.01)),它将控制权交还给ioloop
  3. qsize()是调用的权利,但由于我没有运行/调试这个并且我会采用不同的方法(现有池),因此很难在这里找到问题。