首页 > 技术文章 > 协程

Archer-Fang 2019-04-09 15:57 原文

和多线程比,协程有何优势?

最大的优势就是协程极高的执行效率。

1.因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

2.第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

代码1:

def consumer():
    while True:
        number=yield#生成器
        print('[CONSUMER] Consuming %s...' % num)
consumer=consumer()
next(consumer)#初始化执行到yield停止
for num in range(0,100):
    print('[PRODUCER] Producing %s...' % num)
    consumer.send(num)

结果:

[PRODUCER] Producing 0...
[CONSUMER] Consuming 0...
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
...

 

解释:

  1.代码中创建了一个叫做consumer的协程,并且在主线程中生产数据,协程中消费数据。

  2.其中 yield 是python当中的语法。当协程执行到yield关键字时,会暂停在那一行,等到主线程调用send方法发送了数据,协程才会接到数据继续执行。

但是,yield让协程暂停,和线程的阻塞是有本质区别的。协程的暂停完全由程序控制,线程的阻塞状态是由操作系统内核来进行切换。

因此,协程的开销远远小于线程的开销。

代码2:

def consumer():
    r = ''
    while True:
        n = yield r#由yield得到n的值,并且在执行完循环以后返回r,停在这个位置
if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None)#初始化,停在yield处
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r=c.send(n)#由yield返回的结果
        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

解释:

  1. 首先调用c.send(None)启动生成器;
  2. 然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
  3. consumer通过yield拿到消息,处理,又通过yield把结果传回;
  4. produce拿到consumer处理的结果,继续生产下一条消息;
  5. produce决定不生产了,通过c.close()关闭consumer,整个过程结束。

推荐阅读