zoukankan      html  css  js  c++  java
  • tornado用户指引(二)------------tornado协程实现原理和使用(一)

    摘要:Tornado建议使用协程来实现异步调用。协程使用python的yield关键字来继续或者暂停执行,而不用编写大量的callback函数来实现。(在linux基于epoll的异步调用中,我们需要自己显式的为异步执行结果安装大量的callback函数).协程的使用和编写异步代码一样简单,而且省去了线程的开销。协程使编写并发程序更加容易,而且没有上下文切换的开销。举例:
    from tornado import gen

    @gen.coroutine
      def fetch_coroutine(url)
    Tornado建议使用协程来实现异步调用。

    协程使用python的yield关键字来继续或者暂停执行,而不用编写大量的callback函数来实现。(在linux基于epoll的异步调用中,我们需要自己显式的为异步执行结果安装大量的callback函数).

    协程的使用和编写异步代码一样简单,而且省去了线程的开销。

    协程使编写并发程序更加容易,而且没有上下文切换的开销。

    举例:

    from tornado import gen
    @gen.coroutine
    def fetch_coroutine(url):
      http_client = AsyncHTTPClient()
      response = yield http_client.fetch(url)
    # 在python3.3以前的版本中, 在一个生成器函数中返回值是不允许的。你需要通过抛出异常的方式来达到相同的目的。
    return response.body

    @gen.coroutine是tornado实现的一个生成器,用来将fetch_coroutine函数包装为一个协程,可以把这个协程当作一个和线程等价的执行体。这个执行体会被tornado总的ioloop调用,并在需要阻塞时切换到其它协程执行,当阻塞调用完成时,ioloop会继续执行这个就绪的协程。通过这样的方式,可以在一个线程中执行多个协程,而且不会因为某个协程阻塞而阻塞其它就绪的协程。

    实现原理:

    包装后的函数会返回一个Future,当这个协程真正执行完成后,会设置Future的执行结果。可以通过yield来等待这个协程执行完成并得到结果。

    当协程执行yield http_client.fetch时,由于这个操作是一个网络I/O操作,属于阻塞操作。因此这个协程会暂停执行,进而tornado总的ioloop可以执行其它协程。

    在协程里面,yield语句阻塞的函数需要返回一个Future,这个Future代表了一个异步执行体,并在异步操作执行完成时设置Future的结果,tornado会在Future执行完成时,将Future的执行结果通过生成器的send方法将值传回yield语句,进而唤醒阻塞的协程继续运行。

    在实现上,http_client.fetch操作会通过将fd加入tornado ioloop的方式实现真正的异步操作,当fetch真正成功时,即epoll返回时,会设置Future的结果,并将此协程唤醒继续执行。

    综上所述,我们要利用tornado的协程功能,需要用@gen.coroutine包装我们的函数,并在需要阻塞的地方用yield语句阻塞。阻塞的代码需要返回一个Future,并通过某种异步方式将Future的执行结果设置好。

    使用tornado协程举例:

    1.我们可以在协程不执行任何阻塞操作,这样协程会一直执行直到完成:

    我们创建2个协程和一个总的协程,由于协程里没有阻塞操作,所以实际上两个协程是顺序执行完成的。

    from tornado import gen
    from tornado.ioloop import IOLoop

    @gen.coroutine
    def cor(n,str):
      for i in range(n):
        print(str,i)
      return 

    @gen.coroutine
    def main():
      cor(3,"first")
      cor(4,"second")
    IOLoop.instance().run_sync(main)

    2.有阻塞操作的协程: 我们在协程循环中增加了睡眠操作,这个sleep是tornado框架实现的,注意上面分析的过程,这个yield需要返回一个future. 另外,在main中我们也增加了yield操作,是因为要等待2个协程执行完再结束ioloop.否则程序会直接结束。 这样,可以看到2个协程交替执行,sleep操作并不会阻塞另外一个协程。

    from tornado import gen
    from tornado.ioloop import IOLoop

    @gen.coroutine
    def cor(n,str):
      for i in range(n):
      print(str,n)
      yield gen.sleep(1)
     return 

    @gen.coroutine
    def main():
      cor(3,"first")
      cor(3,"second")
      yield gen.sleep(3)
    IOLoop.instance().run_sync(main)

    3.如果把2中main函数代码改成下面这样,这样main协程就会等待第一个协程执行完,才会执行第2个协程。
    @gen.coroutine
    def main():
      yield cor(3,"first")
      yield cor(3,"second")
    IOLoop.instance().run_sync(main)

  • 相关阅读:
    EBS SQL > Form & Report
    oracle sql 优化分析点
    MRP 物料需求计划
    MRPII 制造资源计划
    Barcode128 应用实务
    Oracle SQL语句优化技术分析
    APPSQLAP10710 Online accounting could not be created. AP Invoice 无法创建会计分录
    Oracle数据完整性和锁机制
    ORACLE Responsibility Menu Reference to Other User
    EBS 常用 SQL
  • 原文地址:https://www.cnblogs.com/b02330224/p/10200902.html
Copyright © 2011-2022 走看看