协程基础
定义:
协程,微线程。协程的本质是一个单线程程序,所以协程不能使用计算机多核资源。
作用:
能够高效的完成并发任务,占用较少的资源。 因此协程的并发量较高
原理:
通过记录应用层的上下文栈区,实现在运行中进行上下文跳转,达到可以选择性地运行想要运行的部分,以此提高程序的运行效率。
优点:
消耗资源少
无需切换开销
无需同步互斥
IO并发性好
缺点:
无法利用计算机多核
python中的协程使用
yield --> 协程实现的基本关键字
基于yield封装实现的第三方库:
greelet
greenlet.greenlet(func) 生成协程对象
gr.switch() 选择要执行的协程对象并记录执行位置
gevent : 基于greenlet
1.将协程事件封装为函数
2. 生成协程对象 gevent.spawn(func,argv)
功能: 生成协程对象
参数: func 协程函数
argv 给协程函数传参
3. 回收协程 gevent.joinall(list)
功能: 回收协程
参数: 列表 将要回收的协程放入列表
4. gevent.sleep(n)
功能: 设置协程阻塞,让协程跳转
参数: n 阻塞时间
from gevent import monkey
monkey.patch_all()
功能:修改套接字的IO阻塞行为
* 必须在socket导入之前使用
greenlet测试
#测试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() # 启动协程1
#打印结果: 12 56 34 78
gevent测试
#gevent模块测试
import gevent
def foo(a,b):
print('a = {}, b = {}'.format(a,b))
gevent.sleep(2)
print('Runing foo again')
def bar():
print('Runing in bar')
gevent.sleep(3)
print('Runing bar again')
#生成协程
f = gevent.spawn(foo,1,2)
g = gevent.spawn(bar)
print('==============')
gevent.joinall([f,g])
print('%%%%%%%%%%%%%%')
gevent.monkey.patch_all()处理后的高并发协程
import gevent
from gevent import monkey
monkey.patch_all()
from socket import *
from time import ctime
def server(port):
#接收客户端连接
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(('0.0.0.0',port))
s.listen(3)
while True:
c,addr = s.accept()
print('Connect from {}'.format(addr))
#handler(c) 循环模型服务器一次只能处理一个请求
gevent.spawn(handler,c,addr) # 协程高并发处理请求
def handler(c,addr):
#处理客户端请求
while True:
data = c.recv(1024)
if not data:
print('连接断开:{}'.format(addr))
break
print(data.decode())
c.send(ctime().encode())
c.close()
if __name__ == '__main__':
port = 8888
s = server(port)