虽然CPython(标准Python)能够通过生成器来实现协程,但使用起来还并不是很方便。
与此同时,Python的一个衍生版 Stackless Python实现了原生的协程,它更利于使用。
于是,大家开始将 Stackless 中关于协程的代码单独拿出来做成了CPython的扩展包。
这就是 greenlet 的由来,因此 greenlet 是底层实现了原生协程的 C扩展库
yield
的使用#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2018/10/17 11:47
# @Author : DoubleChina
# @Site :
# @File : GeventTest.py
# @Software: PyCharm
# yield
# 迭代器 iterable,itertor ,iterion
#
def fib(n):
index = 0
a = 0
b = 1
while index < n:
# 会暂停,阻塞,会返回值
# c是接受外面的数据, b是把值传输给外面
c = yield b
print('task...{}'.format(c))
a, b = b, a + b
index += 1
def yield_test():
f = fib(10)
# 从循环中返回一个值
# print(f.__next__())
n = next(f)
while True:
print(n)
try:
n = f.send(3)
except StopIteration:
break
if __name__ == '__main__':
yield_test()
# 协程就理解为可以切换的函数或者生成器
yield
实现生产者和消费者
def Cunsumer():
r = ''
while True:
n = yield r
if not n:
return
print('Cunsumer{}'.format(n))
r = '200'
def Produce(c):
c.send(None) # 启动生成器,把代码运行到yield这样
n = 0
while n < 5:
n = n + 1
r = c.send(n)
print('Produce{}'.format(r))
c.close()
if __name__ == '__main__':
c = Cunsumer()
Produce(c)
greenlet
#安装: greenlet
pip install greenlet
#安装:gevent
pip install gevent
greenlet
实现生产者和消费者greenlet
优势:
from greenlet import greenlet
import random
import time
def Producer():
while True:
item = random.randint(0, 10)
print('生成了{}'.format(item))
c.switch(item) # 切到c
time.sleep(1)
def Consumer():
while True:
item = p.switch() # 切到P
print('消费了{}'.format(item))
if __name__ == '__main__':
c = greenlet(Consumer)
p = greenlet(Producer)
c.switch()
gevent
详解gevent
通过greenlet
实现协程,核心就是在遇到IO操作,会自动切换到其他的协程上
虽然,我们有了 基于 epoll 的回调式编程模式,但是却难以使用。
即使我们可以通过配合 生成器协程 进行复杂的封装,以简化编程难度。
但是仍然有一个大的问题: 封装难度大,现有代码几乎完全要重写
gevent,通过封装了 libev(基于epoll) 和 greenlet 两个库。
帮我们做好封装,允许我们以类似于线程的方式使用协程。
以至于我们几乎不用重写原来的代码就能充分利用 epoll 和 协程 威力。
优势:
gevent
#记得把他写在第一行
from gevent import monkey
# 会把python标准库中的一些阻塞操作变为非阻塞
monkey.patch_all()
import gevent
import time
def test1():
print(12)
gevent.sleep(2)
print(34)
def test2():
print(56)
gevent.sleep(1)
print(78)
if __name__ == '__main__':
# spawn 启动协程,参数就是函数的名字
# joinall 阻塞当前流程,执行给定的 greenlet
gevent.joinall([gevent.spawn(test1), gevent.spawn(test2)])
print(1111)
gevent
实现队列from gevent import monkey
monkey.patch_all()
from gevent.queue import Queue
import gevent
import random
queue = Queue(3)
def Producer(queue):
while True:
item = random.randint(0, 10)
print('生成了{}'.format(item))
queue.put(item)
gevent.sleep(1)
def Consumer(queue):
while True:
item = queue.get()
print('消费了{}'.format(item))
if __name__ == '__main__':
# spawn 启动协程,参数就是函数的名字
# joinall 阻塞当前流程,执行给定的 greenlet
g1 = gevent.spawn(Producer, queue)
g2 = gevent.spawn(Consumer, queue)
# 阻塞(一阻塞就切换协程)
gevent.joinall([g1, g2])