一、协程
定义:纤程,微线程。本质上只是一个线程在运行。
功能特点:通过应用层程序,记录上下文栈区,实现在程序执行过程中的跳跃执行。由此可以选择不阻塞的部分执行以提升运行效率。
优点:
资源消耗少
无需多线程那样进行多核之间的切换
无需同步互斥操作
IO并发性好
缺点:
无法利用计算机的多核资源
python实现协程的基本手段:yield
第三方工具:
greenlet gevent evenless stackless
sudo pip3 install greenlet
sudo pip3 install gevent
实际项目通常采用:多进程+协程的方式,实现多核高并发。
二、协程模块
1、greenlet
gr = greenlet.greenlet()
gr.switch()
2、gevent
* 将协程事件封装为函数
* 通过gevent将函数生成对应的协程对象
* 通过协程对象完成协程功能的实现
gevent.spawn(func,argv)
功能:将事件变为协程事件并启动
参数:func 出入一个函数变为协程
argv 给func位置传参
返回值:协程对象
gevent.joinall([g1,g2,g3.....])
功能:阻塞回收协程
参数:列表 要回收的协程对象
gevent.sleep(n)
功能:可以模拟IO阻塞的情况
from gevent import monkey
monkey.patch_all()
功能 :修改socket的阻塞行为
* 必须在导入socket之前调用
三、示例
1、greenlet
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() #启动gr1代表的协程
2、gevent
import gevent
def foo(a,b):
print("Running in foo",a)
gevent.sleep(2)
print("switch to foo again")
def bar():
print("Running in bar")
gevent.sleep(3)
print("switch to bar again")
#将两个函数变为协程
f = gevent.spawn(foo,1,2)
b = gevent.spawn(bar)
#回收
gevent.joinall([f,b])
3、gevent_monkey
import gevent
from gevent import monkey
#在导入socket前执行,改变socket的阻塞形态
monkey.patch_all()
from socket import *
from time import ctime
def server(port):
s = socket()
s.bind(('0.0.0.0',port))
s.listen(5)
while True:
c,addr = s.accept()
print('Connect from',addr)
gevent.spawn(handler,c)
#处理客户端事件
def handler(c):
while True:
data = c.recv(1024).decode()
if not data:
break
print('recv:',data)
c.send(ctime().encode())
c.clse()
if __name__ == "__main__":
server(8080)