协程,greenlet原生协程库, gevent库
Posted pywjh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了协程,greenlet原生协程库, gevent库相关的知识,希望对你有一定的参考价值。
yield表达式
在了解协程之前,需要先了解一下生成器中的yield,它不仅可以当做生成器,还能当做一个表达式来使用(yield)
def func(): x = (yield) print(x) x = (yield) g = func() print(next(g)) # 这是第一个yield,就暂停了 g.send(‘hello world‘) # 恢复暂停位置,将第一个yield赋值, # x = hello world,然后又执行到yield,暂停 --> None hello world Process finished with exit code 0
需要注意的是: send跟next一样,可以继续暂停的执行,并把send括号里面的东西变成返回值
没有next开始,就不能使用send!
协程下的生产者与消费者问题
import random, time def consumer(): while True: item = (yield) # 接收send的传递内容 print(‘消费了%s‘ % item) time.sleep(1) def producer(consumer): # 主函数 next(consumer) # 开启协程 while True: item = random.randint(0, 99) print(‘生产了%s‘ % item) consumer.send(item) # 发送 time.sleep(1) c = consumer() # 生成器对象 producer(c)
greenlet原生协程
greenlet属于三方库,通过 pip install greenlet 安装
什么是greenlet呢?
CPython(标准python)能够通过生成器来实现协程,但使用起来并不方便而python的衍生版Stackless python,实现了原生的协程,便于利用。
于是将stackless中关于协程的代码单独拿出来做成了CPython的扩展包
也就是python环境下的原生协程包
greenlet的价值
一 高性能的远程协程
二 语义更加明确的显示切换
三 直接将函数包装成协程,保持原有代码风格
greenlet下的生产者与消费者问题
from greenlet import greenlet from time import sleep from random import randint def consumer(): while True: item = p.switch() # 切换p,开始暂停,等待恢复(只有恢复的时候才能收到数据) print(‘消费了%s‘ % item) sleep(1) def producer(): while True: item = randint(0, 99) print(‘生产了%s‘ % item) c.switch(item) # 暂停当前协程,并且切换到指定的协程,传参 sleep(1) c = greenlet(consumer) # 直接封装成协程 p = greenlet(producer) c.switch() # 相当于next的作用,开启协程
gevent协程
什么是gevent?
gevent开始之前可以先了解一下IO多路复用的epoll
gevent通过封装了libev(基于epoll)和greenlet两个库,可以实现类似线程方式的协程
gevent = epoll + greenlet
gevent的价值是什么?
遇到阻塞就切换到另一个协程继续执行
一 使用基于epoll的libev来避开阻塞
二 使用基于gevent的高效协程来切换执行
三 只有阻塞的时候切换,没有轮询的开销,也没有线程的开销
gevent实现并发服务器
from gevent import monkey; monkey.patch_socket() # 猴子补丁,将socket替换成一个封装了epoll的socket from socket import socket import gevent server = socket() # 封装好的socket server.bind((‘‘, 7788)) server.listen(1000) def recv(conn): while True: recv_date = conn.recv(1024).decode() if recv_date: print(recv_date) conn.send(recv_date.encode()) else: conn.close() while True: conn, addr = server.accept() # 生成一个协程,并将conn作为参数传入 gevent.spawn(recv, conn)
gevent实现生产者与消费者问题
import gevent from gevent import monkey; monkey.patch_all() # all是所有的能切换成协程的地方全部切换,他包含了socket,一般情况下都是用all from random import randint from time import sleep from gevent.queue import Queue # gevent里面的队列 queue = Queue(3) def consumer(): while True: item = queue.get() # 空就阻塞 print(‘消费了%s‘ % item) sleep(1) def producer(): while True: item = randint(0, 99) queue.put(item) # 满就阻塞 epoll阻塞就切换 print(‘生产了%s‘ % item) sleep(1) c = gevent.spawn(consumer) #封装成协程 p = gevent.spawn(producer) gevent.joinall([c, p]) # 等待传入协程结束
以上是关于协程,greenlet原生协程库, gevent库的主要内容,如果未能解决你的问题,请参考以下文章