协程

协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程。
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:
协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。
 
# 协程: 协作式,非抢占式的程序
# A-->B-->A-->ChildProcessError
# yield(协程)
# 用户态的切换
# 关键点:什么时候切换
 
 1 import time
 2 
 3 """
 4 传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。
 5 如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高。
 6 """
 7 # 注意到consumer函数是一个generator(生成器):
 8 # 任何包含yield关键字的函数都会自动成为生成器(generator)对象
 9 
10 def consumer():
11     r = ''
12     while True:
13         # 3、consumer通过yield拿到消息,处理,又通过yield把结果传回;
14         #    yield指令具有return关键字的作用。然后函数的堆栈会自动冻结(freeze)在这一行。
15         #    当函数调用者的下一次利用next()或generator.send()或for-in来再次调用该函数时,
16         #    就会从yield代码的下一行开始,继续执行,再返回下一次迭代结果。通过这种方式,迭代器可以实现无限序列和惰性求值。
17         n = yield r
18         if not n:
19             return
20         print('[CONSUMER] ←← Consuming %s...' % n)
21         time.sleep(1)
22         r = '200 OK'
23 def produce(c):
24     # 1、首先调用c.next()启动生成器
25     next(c)
26     n = 0
27     while n < 5:
28         n = n + 1
29         print('[PRODUCER] →→ Producing %s...' % n)
30         # 2、然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
31         cr = c.send(n)
32         # 4、produce拿到consumer处理的结果,继续生产下一条消息;
33         print('[PRODUCER] Consumer return: %s' % cr)
34     # 5、produce决定不生产了,通过c.close()关闭consumer,整个过程结束。
35     c.close()
36 
37 
38 if __name__=='__main__':
39     # 6、整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。
40     c = consumer()
41     produce(c)
yield实现协程

 

from greenlet import greenlet
 
def test1():
    print (12)
    gr2.switch()
    print (34)
    gr2.switch()
 
def test2():
    print (56)
    gr1.switch()
    print (78)
 
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
greenlet实现协程

 

"""
第三方的gevent为Python提供了比较完善的协程支持。
gevent是第三方库,通过greenlet实现协程,其基本思想是:
当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。
"""import gevent
import time

def foo():
    print("running in foo")
    gevent.sleep(2)
    print("switch to foo again")

def bar():
    print("switch to bar")
    gevent.sleep(4)
    print("switch to bar again")

start=time.time()

gevent.joinall(
    [
        gevent.spawn(foo),
        gevent.spawn(bar)
    ]
)

print(time.time()-start)
gevent实现协程

 

posted @ 2019-02-27 22:25  李小样  阅读(76)  评论(0编辑  收藏  举报