版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/happyAnger6/article/details/51291221
几种常用的协程方式:

1.回调函数

如果你要执行的异步代码是基于回调函数而不是基于Future的,你可以将异步代码通过Task装饰起来。这样Task装饰器会为你添加callback并返回一个Future,这样你就可以用yield来执行异步代码。

@gen.coroutine
def call_task():
# Note that there are no parens on some_function.
# This will be translated by Task into
# some_function(other_args, callback=callback)
  yield gen.Task(some_function, other_args)
在some_function里,你可以执行基于回调函数的异步代码。gen.Task会为你设置好一个callback并通过callback参数传递给some_function,你在some_function内部将callback传递给异步代码所需的callback即可。

2.调用阻塞函数

调用阻塞函数最简单的办法是通过使用ThreadPoolExecutor,它会返回一个Future.

thread_pool = ThreadPoolExecutor(4)

@gen.coroutine
def call_blocking():
  yield thread_pool.submit(blocking_func, args)

3.并行

coroutine装饰器能够识别Future的列表或字典,能够并行执行它们并等待全部完成。

@gen.coroutine
def parallel_fetch(url1, url2):
  resp1, resp2 = yield [http_client.fetch(url1),
  http_client.fetch(url2)]

@gen.coroutine
def parallel_fetch_many(urls):
  responses = yield [http_client.fetch(url) for url in urls]
  # responses is a list of HTTPResponses in the same order

@gen.coroutine
def parallel_fetch_dict(urls):
  responses = yield {url: http_client.fetch(url) for url in urls}
  # responses is a dict {url: HTTPResponse}

4.在yield前插入其它代码

有时候,你需要暂存一个Future而不立即yield它。在此之前可以执行一些其它操作。

@gen.coroutine
def get(self):
  fetch_future = self.fetch_next_chunk()
  while True:
    chunk = yield fetch_future #这里对取到的Future执行yield
    if chunk is None: break
    self.write(chunk)
    fetch_future = self.fetch_next_chunk() #先得到Future而不立刻对其yield
    yield self.flush()

5.循环

由于在python没有办法对for和while循环的每次迭代yield并同时获取结果,所以在循环中使用协程需要一些技巧。

你需要将循环条件和访问结果分开进行,下面的例子演示了这一点:

motor是一个mongodb的python api,它的实现也是基于协程方式,可以十分方便地在tornado中使用它。

import motor
db = motor.MotorClient().test

@gen.coroutine
def loop_example(collection):
  cursor = db.collection.find()
  while (yield cursor.fetch_next):
    doc = cursor.next_object()

6.在后台执行

PeriodicCallback(用于定期地执行一个函数)在协程中并不十分常用。你可以在协程中使用一个循环,在循环中使用tornado.gen.sleep达到同样的效果。

@gen.coroutine

def minute_loop():
  while True:
    yield do_something()
    yield gen.sleep(60)

# Coroutines that loop forever are generally started with
# spawn_callback().
IOLoop.current().spawn_callback(minute_loop)
有时候,你可能需要执行一个更复杂的循环逻辑。比如,上面的例子中循环体每60+N s运行一次,N是do_something()函数执行的时间.如果你想精确控制每次循环执行时间为60s,你可以像下面这样做:

@gen.coroutine
def minute_loop2():
  while True:
    nxt = gen.sleep(60) # 启动一个定时器并不yield它.
    yield do_something() # 在执行定时器的同时执行函数
    yield nxt # 此时再等待定时器超时.

---------------------
作者:self-motivation
来源:CSDN
原文:https://blog.csdn.net/happyAnger6/article/details/51291221
版权声明:本文为博主原创文章,转载请附上博文链接!

tornado用户指引(四)------tornado协程使用和原理(三)的更多相关文章

  1. tornado用户指引(二)------------tornado协程实现原理和使用(一)

    摘要:Tornado建议使用协程来实现异步调用.协程使用python的yield关键字来继续或者暂停执行,而不用编写大量的callback函数来实现.(在linux基于epoll的异步调用中,我们需要 ...

  2. tornado用户指引(三)------tornado协程使用和原理(二)

    Python3.5  async和await async和await是python3.5引入的2个新的关键字(用这两个关键字编写的函数也称之为"原生协程"). 从tornado4. ...

  3. python并发编程之进程、线程、协程的调度原理(六)

    进程.线程和协程的调度和运行原理总结. 系列文章 python并发编程之threading线程(一) python并发编程之multiprocessing进程(二) python并发编程之asynci ...

  4. GO GMP协程调度实现原理 5w字长文史上最全

    1 Runtime简介 Go语言是互联网时代的C,因为其语法简洁易学,对高并发拥有语言级别的亲和性.而且不同于虚拟机的方案.Go通过在编译时嵌入平台相关的系统指令可直接编译为对应平台的机器码,同时嵌入 ...

  5. 深入浅出!从语义角度分析隐藏在Unity协程背后的原理

    Unity的协程使用起来比较方便,但是由于其封装和隐藏了太多细节,使其看起来比较神秘.比如协程是否是真正的异步执行?协程与线程到底是什么关系?本文将从语义角度来分析隐藏在协程背后的原理,并使用C++来 ...

  6. Golang源码探索(二) 协程的实现原理

    Golang最大的特色可以说是协程(goroutine)了, 协程让本来很复杂的异步编程变得简单, 让程序员不再需要面对回调地狱, 虽然现在引入了协程的语言越来越多, 但go中的协程仍然是实现的是最彻 ...

  7. Golang源码探索(二) 协程的实现原理(转)

    Golang最大的特色可以说是协程(goroutine)了, 协程让本来很复杂的异步编程变得简单, 让程序员不再需要面对回调地狱,虽然现在引入了协程的语言越来越多, 但go中的协程仍然是实现的是最彻底 ...

  8. 协程概念,原理及实现(c++和node.js实现)

    协程 什么是协程 wikipedia 的定义: 协程是一个无优先级的子程序调度组件,允许子程序在特点的地方挂起恢复. 线程包含于进程,协程包含于线程.只要内存足够,一个线程中可以有任意多个协程,但某一 ...

  9. tornado 协程的实现原理个人理解;

    tornado实现协程的原理主要是利用了(1)python里面的generator (2)future类和ioloop相互配合,两者之间的相互配合是通过gen.coroutine装饰器来实现的: 具体 ...

随机推荐

  1. jdbc 块提取方式

    最近使用jdbc方式查询数据,保存为csv文件中.当然你可以在pl/sql中直接查出来,copy to excel就好了.但我想通过程序实现 1 @Test 2 public void test() ...

  2. Linux->Ubuntu配置tomcat开机自动启动

    Ubuntu配置tomcat开机自动启动 我们有时候会有这样一个需求: 在开机的时候就启动一个服务,比如tomcat. 我们可以这样做: 将tomcat目录下/bin中的catalina.sh拷贝到/ ...

  3. 沉淀,再出发:Git的再次思考

    沉淀,再出发:Git的再次思考 一.前言 使用git也有很久了,后来有一段时间一直没有机会去使用,现在想来总结一下自己学习了这么长时间的一些心得感悟,我写的博客一般都是开了一个轮廓和框架,等到以后有所 ...

  4. ZT北大青鸟营业额超20亿到不值一提 衰落的背后

    北大青鸟营业额超20亿到不值一提 衰落的背后 2013-10-18 08:18 王根旺  我要评论 (0) “北大青鸟是个悲剧!”说到曾经的IT培训业巨头,黑马导师.珍品网创始人曹允东惋惜道.在学大创 ...

  5. LDA相关论文汇总

    转:http://blog.csdn.net/pirage/article/details/9467547 LDA理论 David M. Blei, Andrew Y. Ng, and Michael ...

  6. libevent使用event_new和不使用的两种方法

    写两个简单的demo,对照一下各自的方法 #include <sys/types.h> #include <event2/event-config.h> #include &l ...

  7. Intellij IDEA 修改编辑器背景颜色

    对眼睛有益的RGB数值分别是(199,237,204)

  8. Nucleus进程间通信(IPC)方式

    版权声明:本文为博主原创文章,未经博主同意不得转载--"http://blog.csdn.net/suipingsp". https://blog.csdn.net/suiping ...

  9. Git 初始化全局user.name 和 user.email

    git config --global user.name "username" git config --global user.email "email"

  10. luogu P4135 作诗

    嘟嘟嘟 郑重声明:我的前几到分块题写法上都有点小毛病,以这篇为主! 这道题感觉也是分块的基本套路,只不过卡常,得开氧气. 维护俩:sum[i][j]表示前 i 块中,数字 j 出现了多少次,ans[i ...