协程
又叫微线程,coroutine,可以认为是比线程更小的执行单元,自带CPU上下文,。
通俗理解:在一个线程的某个函数,可以再任何地方保存当前函数的一些临时变量等信息,然后切换到另一个函数执行,并且切换的次数和什么时候再切换到原来的函数由开发者自己确定。
协程和线程差异
线程非常耗性能,从系统层面远不止保存和恢复CPU上下文,OS的每个线程都有自己缓存Cache等数据等。协程的切换只是单纯操作CPU上下文
# coding=utf-8
import time
import sys
sys.setrecursionlimit(10000)
def A():
while True:
print("---A---")
yield
time.sleep(0.5)
def B(c):
while True:
print("---B---")
c.__next__()
time.sleep(0.5)
if __name__=="__main__":
a=A()
B(a)
运行结果
---B---
---A---
---B---
---A---
---B---
---A---
---B---
---A---
但是用生成器来做协程感觉不是很优美,greenlet
sudo pip install greenlet#python3导入pip3
#coding=utf-8
from greenlet import greenlet
import time
def test1():
while True:
print("---A---")
gr2.switch()
time.sleep(0.5)
def test2():
while True:
print("---B---")
gr1.switch()
time.sleep(0.5)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
#切换到gr1中运行
gr1.switch()
greenlet的底层代码由C语言写的,运行结果一样
gevent比greenlet更强大,自动切换任务,原理是当一个greenlet遇到耗时操作如访问网络时,会自动切换到其他greenlet,操作完成再切换回来继续执行。
#coding=utf-8
import gevent
def f(n):
for i in range(n):
print gevent.getcurrent(), i
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
运行结果:3个greenlet依次运行而不是交替运行
<Greenlet at 0x10e49f550: f(5)> 0
<Greenlet at 0x10e49f550: f(5)> 1
<Greenlet at 0x10e49f550: f(5)> 2
<Greenlet at 0x10e49f550: f(5)> 3
<Greenlet at 0x10e49f550: f(5)> 4
<Greenlet at 0x10e49f910: f(5)> 0
<Greenlet at 0x10e49f910: f(5)> 1
<Greenlet at 0x10e49f910: f(5)> 2
<Greenlet at 0x10e49f910: f(5)> 3
<Greenlet at 0x10e49f910: f(5)> 4
<Greenlet at 0x10e49f4b0: f(5)> 0
<Greenlet at 0x10e49f4b0: f(5)> 1
<Greenlet at 0x10e49f4b0: f(5)> 2
<Greenlet at 0x10e49f4b0: f(5)> 3
<Greenlet at 0x10e49f4b0: f(5)> 4
gevent切换执行
#coding=utf-8
import gevent
def f(n):
for i in range(n):
print gevent.getcurrent(), i
#⽤来模拟⼀个耗时操作, 注意不是time模块中的sleep
gevent.sleep(1)
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
运行结果 3个greenlet交替运行
<Greenlet at 0x7fa70ffa1c30: f(5)> 0
<Greenlet at 0x7fa70ffa1870: f(5)> 0
<Greenlet at 0x7fa70ffa1eb0: f(5)> 0
<Greenlet at 0x7fa70ffa1c30: f(5)> 1
<Greenlet at 0x7fa70ffa1870: f(5)> 1
<Greenlet at 0x7fa70ffa1eb0: f(5)> 1
<Greenlet at 0x7fa70ffa1c30: f(5)> 2
<Greenlet at 0x7fa70ffa1870: f(5)> 2
<Greenlet at 0x7fa70ffa1eb0: f(5)> 2
<Greenlet at 0x7fa70ffa1c30: f(5)> 3
<Greenlet at 0x7fa70ffa1870: f(5)> 3
<Greenlet at 0x7fa70ffa1eb0: f(5)> 3
<Greenlet at 0x7fa70ffa1c30: f(5)> 4
<Greenlet at 0x7fa70ffa1870: f(5)> 4
<Greenlet at 0x7fa70ffa1eb0: f(5)> 4
gevent版服务器 monkey打补丁,动态修改下边的代码