python  generator与coroutine

协程

简单介绍

协程,又称微线程,纤程,英文名Coroutine。
协程是一种用户态的轻量级线程,又称微线程。
协程拥有自己的寄存器上下文和栈,调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

优缺点

优点:
1.无需线程上下文切换的开销
2.无需原子操作锁定及同步的开销
3.方便切换控制流,简化编程模型
4.高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。
原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。

缺点:
1.无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
但是多进程+协程,可以充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
2.进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序。

协程可以用在哪些场景呢

可以归纳为非阻塞等待的场景,如游戏编程,异步IO,事件驱动。

协程详解

Python对协程的支持是通过generator(生成器)实现的。

要理解生成器,我们先要理解迭代器。什么是迭代器?

在python中一个可以迭代的数据调用iter方法,就可以得到一个迭代器,这个迭代器一定具有next方法,在调用这个迭代器的next方法时,迭代器就回返回它的下一个值,当迭代器中没有值可以返回了,就回抛出一个名为StopIteration的异常,停止迭代。

什么是生成器?

生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。
 生成器是个比较特殊的可迭代对象,它与其他的可迭代对象不太一样的地方,其他的可迭代对象需要调用iter方法,返回个迭代器对象,然后通过迭代器对象去执行next方法,获取迭代器中的值,但是生成器直接可以被迭代,无需执行iter方法。

至少我们现在要明白

1.带有 yield 的函数不再是一个普通函数,而是一个生成器generator.
2.生成器是可以迭代的,使用next()方法.
3.生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常。

4.协程是通过生成器的实现的
5.协程有四个状态,如下:
•'GEN_CREATED' 等待开始执行。
•'GEN_RUNNING' 解释器正在执行。
•'GEN_SUSPENDED' 在 yield 表达式处暂停。
•'GEN_CLOSED' 执行结束。

第一个示例程序

test为生成器,即可以迭代,我们可以使用next方法迭代。

第11行创建生成器test,在python的函数(function)定义中,只要出现了yield表达式(Yield expression),那么事实上定义的是一个generator function, 调用这个generator function返回值是一个generator。

第12行打印生成器。

第14行我们可以了生成器的状态,结果为:GEN_CREATED。

第15行第一次执行next方法,send和next操作都是调用生成器,而第一调用生成器就是启动生成器,启动生成器必须使用next()语句或是send(None)启动生成器,不能使用send发送一个非None的值,例如send(None),程序运行到yield 1,程序在这里暂停执行,并返回1,我们要明白在这里yield有了return的功能,返回了1,而且还暂停了程序。

第16行我们再次打印生成器的状态,结果:GEN_SUSPENDED。

第17行第二次执行next方法,程序运行到yield 2,程序在这里暂停,并返回2。

现在就很清晰了,使用yield可以切出生成器,它还有return的功能,切进生成器可以使用next()方法。

调用生成器的next(),将运行到yield位置,此时暂停执行环境,并返回这条语句yield关键词后面跟随的值。 这是next()的使用方法。

 import inspect
def func1():
yield 1
print("第一个yield执行完成~")
yield 2
print("第二个yield执行完成~")
yield 3
print("第三个yield执行完成~") test = func1()
print(test) print("还未执行next:",inspect.getgeneratorstate(test))
next(test)
print("第一次执行next:",inspect.getgeneratorstate(test))
next(test)
print("第二次执行next:",inspect.getgeneratorstate(test))
next(test)
print("第三次执行next:",inspect.getgeneratorstate(test))
next(test)
print("第四次执行next:",inspect.getgeneratorstate(test))

运行结果:

<generator object func1 at 0x0000019ABDFABB88>
Traceback (most recent call last):
还未执行next: GEN_CREATED
第一次执行next: GEN_SUSPENDED
第一个yield执行完成~
第二次执行next: GEN_SUSPENDED
第二个yield执行完成~
File "C:/Pycham/异步编程/test3.py", line 21, in <module>
第三次执行next: GEN_SUSPENDED
第三个yield执行完成~
next(test)
StopIteration

第二个示例程序

在上面的列子我们使用next()切进了生成器,但是每次切换进生成器,都没有传入参数,接下来将介绍send()方法,send()方法不仅可以切进生成器,而且还可以携带参数。

除了next和send方法,generator还提供了两个实用的方法,throw和close,这两个方法加强了caller对generator的控制。send方法可以传递一个值给generator,throw方法在generator挂起的地方抛出异常,close方法让generator正常结束(之后就不能再调用next send了)。

 import sys
def func2(a):
print('-> Started: a =', a)
b = yield a
print('-> Received: b =', b)
c = yield a + b
print('-> Received: c =', c) test = func2(2)
value = next(test)# 协程执行到`b = yield a`处暂停,等待为b赋值,并返回a
print(value)
value = test.send(88)# 协程执行到`c = yield a + b`处暂停,等待为c赋值,并返回a + b
print(value)
try:
test.send(11)
except StopIteration:
sys.exit(0)

运行结果:

-> Started: a = 2
2
-> Received: b = 88
90
-> Received: c = 11

第三个示例程序

传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:

 import time

 def cumtom(name):
print('%s准备吃包子' %name)
time.sleep(1)
while 1:
count=yield
print('%s吃到第%d个包子' %(name,count)) def producter():
next(con1)
next(con2)
# con1.__next__()
# con2.__next__()
n=1
while 1:
time.sleep(1)
print('已经生产出来%d、%d个包子' %(n,n+1))
#通过send方法通知
con1.send(n)
con2.send(n+1)
n+=2 #cumtom函数里面有yield,这里传递参数,会创建一个生成器对象,(提前做了预处理)
con1=cumtom('cumtom1')
con2=cumtom('cumtom2')
producter()

python generator与coroutine的更多相关文章

  1. python enhanced generator - coroutine

    本文主要介绍python中Enhanced generator即coroutine相关内容,包括基本语法.使用场景.注意事项,以及与其他语言协程实现的异同. enhanced generator 在上 ...

  2. Python高级编程之生成器(Generator)与coroutine(四):一个简单的多任务系统

    啊,终于要把这一个系列写完整了,好高兴啊 在前面的三篇文章中介绍了Python的Python的Generator和coroutine(协程)相关的编程技术,接下来这篇文章会用Python的corout ...

  3. Python高级编程之生成器(Generator)与coroutine(三):coroutine与pipeline(管道)和Dataflow(数据流_

    原创作品,转载请注明出处:点我 在前两篇文章中,我们介绍了什么是Generator和coroutine,在这一篇文章中,我们会介绍coroutine在模拟pipeline(管道 )和控制Dataflo ...

  4. Python高级编程之生成器(Generator)与coroutine(二):coroutine介绍

    原创作品,转载请注明出处:点我 上一篇文章Python高级编程之生成器(Generator)与coroutine(一):Generator中,我们介绍了什么是Generator,以及写了几个使用Gen ...

  5. Python高级编程之生成器(Generator)与coroutine(一):Generator

    转载请注明出处:点我 这是一系列的文章,会从基础开始一步步的介绍Python中的Generator以及coroutine(协程)(主要是介绍coroutine),并且详细的讲述了Python中coro ...

  6. 操作系统OS,Python - 协程(Coroutine)

    留坑 参考: https://en.wikipedia.org/wiki/Coroutine https://zh.wikipedia.org/wiki/%E5%8D%8F%E7%A8%8B http ...

  7. Python generator和yield介绍

    Python生成器(generator)并不是一个晦涩难懂的概念.相比于MetaClass和Closure等概念,其较为容易理解和掌握.但相对于程序结构:顺序.循环和分支而言其又不是特别的直观.无论学 ...

  8. python generator用法

    转自:https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013868196510 ...

  9. [Python] Use a Python Generator to Crawl the Star Wars API

    In this lesson, you will be introduced to Python generators. You will see how a generator can replac ...

随机推荐

  1. Redis 一些高级用法

    延迟消息队列 利用 expire keyspace notification Redis 过期时,会向特定的消息队列发送消息,监听该消息队列 在 redis.conf 修改 notify-keyspa ...

  2. DirectX 图形流水线

    Direct3D 的可编程流水线用来为实时游戏渲染图形(一个词概括——实时渲染) 上面的图是Dx11的实时渲染流水线,Dx的几个版本都是向下兼容的. Input-Assembler Stage: 输入 ...

  3. Bind Enum to Combobox.SelectedIndex

    原文:Bind Enum to Combobox.SelectedIndex Do you mean that you want to bind a variable (not a property) ...

  4. Delphi中的线程类 - TThread详解

    Delphi中的线程类 - TThread详解 2011年06月27日 星期一 20:28 Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本 ...

  5. KEIL MDK编译后的代码量和RAM使用详解

    一般 MCU 包含的存储空间有:片内 Flash 与片内 RAM,RAM 相当于内存,Flash 相当于硬盘.编译器会将一个程序分为好几个部分,分别存储在 MCU 不同的存储区.Keil 工程在编译完 ...

  6. Image Captioning代码复现

    Image caption generation: https://github.com/eladhoffer/captionGen Simple encoder-decoder image capt ...

  7. Windows完成端口与猪肉佬

    首先应该说明的是,我也是第一次使用完成端口.虽然以前偶尔在网上看到完成端口的文章和代码,但真正自己动手写还是第一次,不过我这个人有个特点就是大胆,例如没有写那个界面编程系列前,其实我甚至不知道原来一个 ...

  8. ubuntu QT开发环境(三种方法安装Qt4.8,其中apt-get方法安装QT库最简单)good

    方法一 QT4.8.0库+QT Creator 2.4.1 特别声明:此方法极其耗时间,看电脑性能了.配置configure可减少编译时间 1.下载Qt .进入网址http://qt.nokia.co ...

  9. [Err] 1146 - Table 'performance_schema.session_status' doesn't exist已解决

    刚刚接触MySQL,就往数据库添加数据,就遇到这个问题 解决方案就是找到你安装MySQL的bin目录 然后在cmd输入 mysql_upgrade -u root -p --force 回车,然后输入 ...

  10. Laravel:php artisan key:generate三种报错解决方案,修改默认PHP版本(宝塔面板)

    为了兼容N多个网站,服务器上有3个PHP版本5.3/5.6/7.2.宝塔默认为5.3,但是laravel5.7并不支持,所以在创建线上 .env 环境配置文件,初始化应用配置时候报错了. cp .en ...