深入理解yield(二):yield与协程
转自:http://blog.beginman.cn/blog/133/
协程概念
1.并发编程的种类:多进程,多线程,异步,协程
2.进程,线程,协程的概念区别:
进程:拥有自己独立的堆和栈,既不共享堆也不共享栈,进程由操作系统调度。
线程:线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
协程:协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显式调度
3.协程:
协程可以认为是一种用户态的线程,与系统提供的线程不同点是,它需要主动让出CPU时间,而不是由系统进行调度,即控制权在程序员手上。
4.进程,线程,协程在python中的表现
关于进程,python有multiprocessing
模块进行处理;关于线程,python的Thread
和Threading
处理;关于异步,有各种python框架如Tornado等调用linux下的select
,poll
,epoll
等异步实现;关于协程,由yield
来实现。
5.协程与yield
在廖雪峰的python博客中学习总结协程如下:
1).子程序调用通过栈实现,一个线程执行一个子程序,有明确的执行顺序,而协程不同于此,协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。注意的一点是:如A,B两个子程序, A执行过程中可以去执行B,并不是调用B,B可以中断(挂起)转而回到A.
所以可以看到执行过程在A,B两个子程序中切换,但是A并没有调用B,B的中断可以通过yield
来保存,A,B的执行过程像多线程,但是协程的特点在于一个线程执行。
2).协程的优势:
最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
下面通过多线程的生产者消费者与协程的生产者消费者实例进行演示:
# 多线程
# coding=utf-8
from threading import Thread
from threading import Condition
import time
import random
#为了达到理解效果,这里没有使用简便的Queue
queue = []
condition = Condition()
MAX_LENGTH = 20
#代码实例:http://blog.jobbole.com/52412/
#生产者的工作是产生一块数据,放到buffer中,如此循环。
#与此同时,消费者在消耗这些数据(例如从buffer中把它们移除),每次一块。
#这里的关键词是“同时”。所以生产者和消费者是并发运行的,我们需要对生产者和消费者做线程分离。
#这个为描述了两个共享固定大小缓冲队列的进程,即生产者和消费者。
class ProducerThread(Thread):
def run(self):
nums = range(5)
global queue
while True:
num = random.choice(nums)
condition.acquire() # 锁定以生成数据
if len(queue) == MAX_LENGTH:
print u'队列已满,等待消费中...'
condition.wait() # 线程等待
queue.append(num) # 往队列中生成数据
print "Produced", num
condition.notify() # 通知线程等待的消费者消费数据
condition.release() # 释放线程锁
time.sleep(random.random())
class ConsumerThread(Thread):
def run(self):
global queue
while True:
condition.acquire() #线程锁
if not queue:
print u"队列为空,等待生产者生成数据...."
condition.wait() # 线程等待
num = queue.pop(0) # 消费数据
print "Consumed", num
condition.notify() # 通知线程等待的生产者继续生成数据(生产者线程等待条件是队列已满)
condition.release() # 释放线程锁
time.sleep(2) #执行时间长点,让生产者生成更多数据来测试
ProducerThread().start()
ConsumerThread().start()
传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。
下面改用协程的方式:
# 协程
#生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:
def consumer():
v = None
while 1:
m = yield v
if not m:
return
print "[C]CLine:%s, CProduce:%s" % (m, v)
v = 'range'
def producter():
i = 0
c = consumer()
c.next() # To avoid sending a non-None value to a just-started generator, you need to call next or send(None) first.
while i < 5:
try:
i += 1
print(u'[P]producing...%s' % i)
v = c.send(i)
print(u'[P]CReturn: %s' % v)
except StopIteration:
print 'Done!'
break
c.close()
if __name__ == '__main__':
producter()
执行结果如下:
[P]producing...1
[C]CLine:1, CProduce:None
[P]CReturn: range
[P]producing...2
[C]CLine:2, CProduce:range
[P]CReturn: range
[P]producing...3
[C]CLine:3, CProduce:range
[P]CReturn: range
[P]producing...4
[C]CLine:4, CProduce:range
[P]CReturn: range
[P]producing...5
[C]CLine:5, CProduce:range
[P]CReturn: range
引用廖雪峰python协程的理解:
注意到consumer函数是一个generator(生成器),把一个consumer传入produce后:
首先调用c.next()启动生成器;
然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
consumer通过yield拿到消息,处理,又通过yield把结果传回;
produce拿到consumer处理的结果,继续生产下一条消息;
produce决定不生产了,通过c.close()关闭consumer,整个过程结束。
整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。
最后套用Donald Knuth的一句话总结协程的特点:
“子程序就是协程的一种特例。”
执行动态图如下:
下节要点:
1.Python异步与yield的总结
2.Tornado异步非阻塞实例与yield的总结
作者:BeginMan
网址: http://blog.beginman.cn/blog/133/
在未标明转载的情况下,本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
深入理解yield(二):yield与协程的更多相关文章
- 深入理解协程(二):yield from实现异步协程
原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的第二篇. yield from ...
- yield与send实现协程操作
yield与send实现协程操作 之前我们说过,在函数内部含有yield语句即称为生成器. 下面,我们来看看在函数内部含有yield语句达到的效果.首先,我们来看看以下代码: def foo(): w ...
- PHP下的异步尝试二:初识协程
PHP下的异步尝试系列 如果你还不太了解PHP下的生成器,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunkify ...
- Kotlin Coroutine(协程): 二、初识协程
@ 目录 前言 一.初识协程 1.runBlocking: 阻塞协程 2.launch: 创建协程 3.Job 4.coroutineScope 5.协程取消 6.协程超时 7.async 并行任务 ...
- yield、greenlet与协程gevent
yield 在说明yield之前,我们了解python中一些概念. 在了解Python的数据结构时,容器(container).可迭代对象(iterable).迭代器(iterator).生成器(ge ...
- Python用yield form 实现异步协程爬虫
很古老的用法了,现在大多用的aiohttp库实现,这篇记录仅仅用做个人的协程底层实现的学习. 争取用看得懂的字来描述问题. 1.什么是yield 如果还没有怎么用过的话,直接把yield看做成一种特殊 ...
- PHP yield 分析,以及协程的实现,超详细版(上)
参考资料 http://www.laruence.com/2015/05/28/3038.html http://php.net/manual/zh/class.generator.php http: ...
- python中和生成器协程相关的yield之最详最强解释,一看就懂(一)
yield是python中一个非常重要的关键词,所有迭代器都是yield实现的,学习python,如果不把这个yield的意思和用法彻底搞清楚,学习python的生成器,协程和异步io的时候,就会彻底 ...
- python协程--yield和yield from
字典为动词“to yield”给出了两个释义:产出和让步.对于 Python 生成器中的 yield 来说,这两个含义都成立.yield item 这行代码会产出一个值,提供给 next(...) 的 ...
- 再议Python协程——从yield到asyncio
协程,英文名Coroutine.前面介绍Python的多线程,以及用多线程实现并发(参见这篇文章[浅析Python多线程]),今天介绍的协程也是常用的并发手段.本篇主要内容包含:协程的基本概念.协程库 ...
随机推荐
- html input元素
1.单选框复选框 html中有两种选择框,即单选框和复选框,两者的区别是单选框中的选项用户只能选择一项,而复选框中用户可以任意选择多项,甚至全选.请看下面的例子: 语法:<input type= ...
- IOS控件大全及控件大小
一 视图UIView和UIWindow iphone视图的规则是:一个窗口,多个视图.UIWindow相当于电视机,UIViews相当于演员. 1.显示数据的视图 下面几个类可在屏幕上显示信息: UI ...
- MyEclipse10 添加反编译JadClipse插件
工具/原料 MyEclipse10.0.7+net.sf.jadclipse_3.3.0.jar+jad.exe net.sf.jadclipse_3.3.0.jar+jad.exe下载地址:ht ...
- ThinkPHP3.2.3整合smarty模板(三)
在smarty模板中使用thinkphp框架的U方法时要主要的问题: 1.不能直接使用{:U('Index/index')}: 2.正确的使用方法为:<!--{U("Login/log ...
- ZOJ3545 Rescue the Rabbit
分析 未知定长串中不同已知模板串的出现次数问题,一般做法是AC自动机上dp. 考虑背包,\(dp(i,j,k)\)表示当前串长为\(i\),在AC自动机上对应节点\(j\),已匹配的模板串的状态为\( ...
- 读取地址C语言
就是黑点820要算的16位地址(A B C D E F) ************************************************************ C语言中要输出地址时 ...
- MySQL Disk--NAND Flash原理
====================================================== NAND Flash最小存储单元: 写数据操作: 通过对控制闸(Control Gate) ...
- day41 mysql 学习 练习题 重要*****
MySQL 练习题[二1.表如下: 收获和注意点:***** #1 GROUP by 可以放到where s_id in ()条件局后边 GROUP BY s_id having 详见题12 #2 做 ...
- P·C·L 了解
因为PCL是开源的,所以无论是商用还是研究都是免费的: 赞助商有Open Perception, Willow Garage, NVIDIA, Google, Toyota, Trimble, Urb ...
- 通过直接编码添加折线图到ChartControl
https://documentation.devexpress.com/#WindowsForms/CustomDocument2976 ChartControl lineChart = new C ...