协程

网络编程和并发之协程

一笑奈何 提交于 2020-01-04 05:10:34
一、引入  之前我们学习了线程、进程的概念,了解了在操作系统中 进程是资源分配的最小单位,线程是CPU调度的最小单位。 按道理来说我们已经算是把cpu的利用率提高很多了。但是我们知道无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程、创建线程、以及管理他们之间的切换。   随着我们对于效率的追求不断提高, 基于单线程来实现并发 又成为一个新的课题,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发。这样就可以节省创建线进程所消耗的时间。   为此我们需要先回顾下并发的本质:切换+保存状态   cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长       ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态    一:其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。   为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: #1 yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的

python并发编程之协程

删除回忆录丶 提交于 2020-01-04 05:10:21
阅读目录 一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二 一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质: 切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长 ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 一:其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: #1 yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 #2 send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 单纯地切换反而会降低运行效率 二:第一种情况的切换。在任务一遇到io情况下,切到任务二去执行,这样就可以利用任务一阻塞的时间完成任务二的计算

DAY10-python并发编程之携程

倾然丶 夕夏残阳落幕 提交于 2020-01-04 05:10:10
一、引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长或有一个优先级更高的程序替代了它 ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 一:其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: #1 yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 #2 send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 #串行执行 import time def consumer(res): '''任务1:接收数据,处理数据''' pass def producer(): '''任务2:生产数据''' res=[] for i in range(10000000): res.append(i)

并发编程之协程

天大地大妈咪最大 提交于 2020-01-04 05:09:55
引言 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长或有一个优先级更高的程序替代了它 ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 一:其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: yield可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 #yield功能(可以吧函数暂停住,保存原来的状态)-------------- def f1(): print('first') yield 1 print('second') yield 2 print('third') yield 3 # print(f1())

034_协程

强颜欢笑 提交于 2020-01-04 05:09:40
前言   之前我们学习了线程、进程的概念,了解了在操作系统中 进程是资源分配的最小单位,线程是CPU调度的最小单位。 按道理来说我们已经算是把cpu的利用率提高很多了。但是我们知道无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程、创建线程、以及管理他们之间的切换。   随着我们对于效率的追求不断提高, 基于单线程来实现并发 又成为一个新的课题,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发。这样就可以节省创建线进程所消耗的时间。   为此我们需要先回顾下并发的本质:切换+保存状态   cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制), 一种 情况是该任务发生了阻塞, 另外一种 情况是该任务计算的时间过长(每个程序运行一段时间,切换进行)       ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态    一: 其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。    二: 第一种情况的切换。在任务一遇到io情况下,切到任务二去执行,这样就可以利用任务一阻塞的时间完成任务二的计算,效率的提升就在于此。 协程介绍    协程: 是单线程下的并发,又称微线程

python 协程

拈花ヽ惹草 提交于 2020-01-04 05:09:27
协程 之前我们了解了线程、进程的概念,了解了在操作系统中 进程是资源分配的最小单位,线程是CPU调度的最小单位。 按道理来说我们已经算是把cpu的利用率提高很多了。但是我们知道无论是创建多进程还是创建多线程,都要消耗一定的时间来创建进程、线程、以及管理他们之间的切换。随着我们对于效率的追求不断提高, 基于单线程来实现并发 又成为一个新的课题,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发。这样就可以节省创建线进程所消耗的时间。为此我们需要先回顾下并发的本质:切换+保存状态。 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长。 好了知道规律,我们就可以想一个办法来欺骗操作系统,那如何欺骗呢?就是欺骗操作系统我一直处于很忙的状态,这样程序便一直处于就绪和执行的状态。这也就是协程的本质,程序只在就绪和执行状态,而不在阻塞状态。从而提高程序被CPU执行的机会。 下面我们使用yield生成器来骗操作系统: import time def consumer(): '''任务1:接收数据,处理数据''' while True: x=yield print(x,end=" ") def producer(): '''任务2:生产数据''' g=consumer() next(g)

第三十二章:协程

拈花ヽ惹草 提交于 2020-01-04 05:09:08
引子 上一节中我们知道GIL锁将导致CPython无法利用多核CPU的优势,只能使用单核并发的执行。很明显效率不高,那有什么办法能够提高效率呢? 效率要高只有一个方法就是让这个当前线程尽可能多的占用CPU时间,如何做到? 任务类型可以分为两种 IO密集型 和 计算密集型 对于计算密集型任务而言 ,无需任何操作就能一直占用CPU直到超时为止,没有任何办法能够提高计算密集任务的效率,除非把GIL锁拿掉,让多核CPU并行执行。 对于IO密集型任务任务,一旦线程遇到了IO操作CPU就会立马切换到其他线程,而至于切换到哪个线程,应用程序是无法控制的,这样就导致了效率降低。 如何能提升效率呢?想一想如果可以监测到线程的IO操作时,应用程序自发的切换到其他的计算任务,是不是就可以留住CPU?的确如此 一、单线程实现并发 单线程实现并发这句话乍一听好像在瞎说 首先需要明确并发的定义 并发:指的是多个任务同时发生,看起来好像是同时都在进行 并行:指的是多个任务真正的同时进行 早期的计算机只有一个CPU,既然CPU可以切换线程来实现并发,那么为何不能再线程中切换任务来并发呢? 上面的引子中提到,如果一个线程能够检测IO操作并且将其设置为非阻塞,并自动切换到其他任务就可以提高CPU的利用率,指的就是在单线程下实现并发。 如何能够实现并发呢 并发 = 切换任务+保存状态,只要找到一种方案

python并发编程(二):协程

三世轮回 提交于 2020-01-04 05:08:58
'''协程: 1. 协程的定义: 1) 是一种用户态的轻量级线程, 即协程是由用户程序自己控制调度的 2) 是一种协作而非抢占式的处理并发方式, A --> B ---> A --> C 3) 协程的切换属于程序级别的, 操作系统不需要切换 2. 协程的特点: 1) 协程本身是一个线程, 是用户态的切换 2) 相比线程优点: 1> 切换没有消耗 2> 修改共享程序不需要加锁 3) 相比线程缺点: 一旦引入协程,就需要检测单线程下所有的IO行为, 实现遇到IO就切换,少一个都不行,因为一旦一个任务阻塞了,整个线程就阻塞了 3. 并发要求: 1) 要控制多个任务之间的切换 2) 切换之前要把当前任务状态保存下来 (yield, greenlet无法检测IO) 3) 可以自动检测IO操作, 在IO阻塞下发生切换 (geven可以检测IO) ''' # 协程'''协程实现: 1. 生成器: yield, next(g), g.send(value) 用法: yield # 可以保存状态 g = generator() # 创建生成器 next(g) # 检测到最近yield位置, 执行yield之前的代码 g.send(value) # 检测当前yield的位置,把值通过该yield传入,执行下一个yield到该yield之间的代码, 然后返回 2. greenlet:

python 并发协程

拜拜、爱过 提交于 2020-01-04 05:08:48
一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长 ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态 其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法,我们来简单复习一下: #1 yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 #2 send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 单纯地切换反而会降低运行效率 #串行执行 import time def consumer(res): '''任务1:接收数据,处理数据''' pass def producer(): '''任务2:生产数据''' res=[] for i in range(10000000): res.append(i)

并发编程之 协程

≯℡__Kan透↙ 提交于 2020-01-04 05:08:31
协程 (单线程下实现并发)   进程:资源单位   线程:执行单位    协程:单线程下实现并发 并发:切换+保存状态 程序员自己通过代码自己检测程序中的IO 一旦遇到了IO自己通过代码切换 给操作系统的感觉就是你这个线程没有任何的IO 从而提升代码的运行效率 切换+保存状态一定能够提升效率吗?   1.当任务是IO密集型的情况下 提升效率   2.当任务是计算密集型的情况下 降低效率 接下来 我们进行验证 1.在计算密集型的情况下,通过切换+保存状态 效率到底是降低了还是提升了呢? 这是串行执行的时间: # 串行执行 0.8540799617767334 import time def func1(): for i in range(10000000): i+1 def func2(): for i in range(10000000): i+1 start = time.time() func1() func2() stop = time.time() print(stop - start) 下面是切换+保存状态的执行时间: #基于yield并发执行 1.3952205181121826 import time def func1(): while True: 10000000+1 yield def func2(): g=func1() for i in range