2017-05-26 91 views
1

当我在简单的Tornado应用程序中运行此处理程序并使用curl发出两个请求时,它不会并行运行。当我想要打印“1 1 2 2 3 3 4 4 5 5”时,打印出“1 2 3 4 5 1 2 3 4 5”。为什么在Tornado协同程序中time.sleep并行运行?

class SleepHandler(RequestHandler): 
    def get(self): 
     for i in range(5): 
      print(i) 
      time.sleep(1) 

我在做什么错了?

回答

3

这样做的原因是,time.sleep阻塞功能:它不允许控制返回IOLoop,使其他处理程序可以运行。

当然,time.sleep通常只是这些示例中的占位符,重点是要显示处理程序中的某些内容变慢时会发生什么。无论真正的代码在做什么,为了实现并发性,阻塞代码必须替换为非阻塞等价物。这意味着三两件事之一:

  • 查找协程友好相当于。对于time.sleep,请改为使用tornado.gen.sleep:

    class CoroutineSleepHandler(RequestHandler): 
        @gen.coroutine 
        def get(self): 
         for i in range(5): 
          print(i) 
          yield gen.sleep(1) 
    

    当此选项可用时,通常是最佳方法。请参阅Tornado wiki以获取可能有用的异步库的链接。

  • 查找基于回拨的等效物。类似于第一种选择,基于回调的库可用于许多任务,但它们比为协程设计的库稍微复杂一些。这些通常与tornado.gen.Task用作适配器:

    class CoroutineTimeoutHandler(RequestHandler): 
        @gen.coroutine 
        def get(self): 
         io_loop = IOLoop.current() 
         for i in range(5): 
          print(i) 
          yield gen.Task(io_loop.add_timeout, io_loop.time() + 1) 
    

    再次,Tornado wiki可以是有用的,以找到合适的库。

  • 在另一个线程上运行阻止码。当异步库不可用时,可以使用concurrent.futures.ThreadPoolExecutor在另一个线程上运行任何阻塞码。这是可用于任何阻挡功能的异步对方是否存在一个通用的解决方案:

    executor = concurrent.futures.ThreadPoolExecutor(8) 
    
    class ThreadPoolHandler(RequestHandler): 
        @gen.coroutine 
        def get(self): 
         for i in range(5): 
          print(i) 
          yield executor.submit(time.sleep, 1) 
    

    参见龙卷风用户指南的Asynchronous I/O chapter更多关于阻塞和异步函数。

+0

我希望你能粘这个答案 –

+0

这就是主意。这是复制[龙卷风常见问题](http://www.tornadoweb.org/en/stable/faq.html#why-isn-t-this-example-with-time-sleep-running-in-parallel)因此所有其他提出这个问题的问题都可以作为这个问题的重复来解决。 –

相关问题