协程:是单线程下的并发,又称微线程,纤程。英文名Coroutine。简单来说:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
1.协程 协程,又称微线程。协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。
协程的优点: - 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级。 - 单线程内就可以实现并发的效果,最大限度地利用cpu。
协程的缺点: - 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程。 - 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程。
Python对协程的支持是通过generator实现的。
在generator中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取由yield语句返回的下一个值。但是Python的yield不但可以返回一个值,它还可以接收调用者发出的参数。
2.实例
一个最简单的协程例子。
import time
def work1():
while True:
print("---work1---")
yield
time.sleep(0.5)
def work2():
while True:
print("---work2---")
yield
time.sleep(0.5)
def main():
w1 = work1()
w2 = work2()
while True:
next(w1)
next(w2)
if __name__ == '__main__':
main()
运行结果:
---work1---
---work2---
---work1---
---work2---
---work1---
---work2---
...
使用协程实现生产者-消费者模型。
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK'
def produce(c):
c.send(None)
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close()
c = consumer()
produce(c)
运行结果:
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK
注意到consumer函数是一个generator,把一个consumer传入produce后:
整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。最后套用Donald Knuth的一句话总结协程的特点:“子程序就是协程的一种特例。”