协程目的:
1、单线程下实现并发:协程
解决方案:一个任务运行的过程中把它打断(保存此时的状态)切换到另一个任务中,运行一段时间再切换回来,反复来回切换
注:并发指的是多个任务看起来是同时运行的
并发实现的本质:切换+保存状态
并发、并行、串行:
并发:看起来是同时运行,切换+保存状态
并行:真正意义上的同时运行,只有在多cpu情况下才实现并行,4个cpu能够并行4个任务
串行:一个任务完完整整地执行完毕才运行下一个任务
例如以下程序中生产者和消费者数据的来回切换:(应用程序自己控制切换及保存状态,速度更快)

import time
def consumer():
'''任务1:接收数据,处理数据'''
while True:
x=yield
def producer():
'''任务2:生产数据'''
g=consumer()
next(g)
for i in range(10000000):
g.send(i)
start=time.time()
#基于yield保存状态,实现两个任务直接来回切换,即并发的效果
#PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.
producer() #1.0202116966247559
stop=time.time()
print(stop-start)
但如果一个程序中是纯计算活的话,来回切换意义不大,如下:
# 纯计算的任务串行执行
import time
def task1():
res=1
for i in range(1000000):
res+=i
def task2():
res=1
for i in range(1000000):
res*=i
start=time.time()
task1()
task2()
stop=time.time()
print(stop-start)
# 纯计算的任务并发执行
import time
def task1():
res=1
for i in range(1000000):
res+=i
yield #切换到task2
def task2():
g=task1()
res=1
for i in range(1000000):
res*=i
next(g) #切换到task1
start=time.time()
#基于yield保存状态,实现两个任务直接来回切换,即并发的效果
#PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.
task2()
stop=time.time()
print(stop-start)打印结果:
0.22888588905334473
0.42775511741638184
可以看出做纯计算任务并发执行的时间是串行执行的2倍,速度慢了
所以单线程下实现并发是为了提高效率,检测多个任务的IO行为,遇到IO再切到自己单线程下的另外一个任务去执行,这样就把单线程下的IO问题给尽可能多的缩减下来(相当于‘欺骗了’操作系统,在操作系统看来你一直处于工作状态,操作系统才不会把cpu拿走),这样单线程就尽可能多的处于计算过程,也就是处于就绪态。
强调:
#1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行) #2. 单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(!!!非io操作的切换与效率无关)
协程优点:
#1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级 #2. 单线程内就可以实现并发的效果,最大限度地利用cpu
缺点:
#1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程 #2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
