Python web框架 Tornado异步非阻塞

 

异步非阻塞

阻塞式:(适用于所有框架,Django,Flask,Tornado,Bottle)
  一个请求到来未处理完成,后续一直等待
  解决方案:多线程,多进程

异步非阻塞(存在IO请求): Tornado(单进程+单线程)
  使用异步非阻塞,需要遵循Tornado框架内部规则,gen

  多个连接请求,连接给服务端,如果是有异步非阻塞的话,服务端会接收所有的请求交由后台处理,等待其他链接的同时,原先连接不断开,直至返回后台处理完成的结果!
  外部请求,连接服务端 或在select中创建Future对象,然后服务端再把请求交给业务处理平台,此时select监听的列表中又会生成一个socket对象,当业务平台对请求处理完成之后就会把信息返回到服务端的select监听列表中,同时对这个Future对象赋值,用于标记服务端是否要给客户端返回请求信息。

  执行流程,本质上都是返回一个future对象,如果对这个对象被set_result了就返回值,否则就是夯住,一直保持连接,不终止请求。

1、基本使用

装饰器 + Future 从而实现Tornado的异步非阻塞

class AsyncHandler(tornado.web.RequestHandler):

  
    @gen.coroutine
    def get(self):
        future = Future()
        future.add_done_callback(self.doing)
        yield future
        # 或
        # tornado.ioloop.IOLoop.current().add_future(future,self.doing)
        # yield future
  
    def doing(self,*args, **kwargs):
        self.write('async')
        self.finish()

  当发送GET请求时,由于方法被@gen.coroutine装饰且yield 一个 Future对象,那么Tornado会等待,等待用户向future对象中放置数据或者发送信号,如果获取到数据或信号之后,就开始执行doing方法。

  异步非阻塞体现在当在Tornaod等待用户向future对象中放置数据时,还可以处理其他请求。

  注意:在等待用户向future对象中放置数据或信号时,此连接是不断开的。

2、同步阻塞和异步非阻塞对比

     同步阻塞

     

class SyncHandler(tornado.web.RequestHandler):

    def get(self):
        self.doing()
        self.write('sync')

    def doing(self):
        time.sleep(10)

异步非阻塞
class AsyncHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        future = Future()
        tornado.ioloop.IOLoop.current().add_timeout(time.time() + 5, self.doing)
        yield future


    def doing(self, *args, **kwargs):
        self.write('async')
        self.finish()

3、httpclient类库

  Tornado提供了httpclient类库用于发送Http请求,其配合Tornado的异步非阻塞使用。

  import tornado.web

   from tornado import gen
   from tornado import httpclient
  
   # 方式一:
   class AsyncHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self*args, **kwargs):
        print('进入')
        http = httpclient.AsyncHTTPClient()
        data = yield http.fetch("http://www.google.com")
        print('完事',data)
        self.finish('6666')
  
   # 方式二:
   # class AsyncHandler(tornado.web.RequestHandler):
   #     @gen.coroutine
   #     def get(self):
   #         print('进入')
   #         http = httpclient.AsyncHTTPClient()
   #         yield http.fetch("http://www.google.com", self.done)
   #
   #     def done(self, response):
   #         print('完事')
   #         self.finish('666')
  
  
  
application = tornado.web.Application([
    (r"/async", AsyncHandler),
])
  
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()