协程回顾

在这里插入图片描述
Python经过yield提供了对协程的基本支持,可是不彻底。而第三方的gevent为Python提供了比较完善的协程支持。python

gevent是第三方库,经过greenlet实现协程,其基本思想是:服务器

当一个greenlet遇到IO操做时,好比访问网络,就自动切换到其余的greenlet,等到IO操做完成,再在适当的时候切换回来继续执行。因为IO操做很是耗时,常常使程序处于等待状态,有了gevent为咱们自动切换协程,就保证总有greenlet在运行,而不是等待IO网络

生成器send方式:

def create_num(all_num):
    a,b = 0,1
    current_num = 0
    while current_num < all_num:
        ret = yield a
        print(ret)
        a,b = b, a+b
        current_num +=1

obj = create_num(10)
ret= next(obj)
print(ret)
ret = obj.send('鲁班七号')
print(ret)
>>>
0
鲁班七号
1

yield完成多任务

import time
def task1():
    while True:
        print("task one")
        time.sleep(1)
        yield
def task2():
    while True:
        print("task 2")
        time.sleep(1)
        yield

def main():
    obj1 =  task1()
    obj2 = task2()
    while True:
       next(obj1)
       next(obj2)
if __name__ == '__main__':
    main()
>>>
task one
task 2
task one
task 2
task one
......

使用greenlet完成多任务

from greenlet import greenlet
import time

def f1():
    while True:
        print('-----A-----')
        gr2.switch()
        time.sleep(0.5)

def f2():
    while True:
        print('-----B-----')
        gr1.switch()
        time.sleep(0.5)
if __name__ == '__main__':
    gr1 = greenlet(f1)
    gr2 = greenlet(f2)
    gr1.switch()

gevent

import gevent
import time

def f1(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        gevent.sleep(1) #模拟一个耗时操做,模拟耗时操做要用gevent里面函数

def f2(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        gevent.sleep(1)

if __name__ == '__main__':
     g1 = gevent.spawn(f1,5)
     g2 = gevent.spawn(f2,5)
     g1.join()
     g2.join()
>>>
<Greenlet at 0x2f598b0: f1(3)> 0
<Greenlet at 0x2f599c0: f2(3)> 0
<Greenlet at 0x2f598b0: f1(3)> 1
<Greenlet at 0x2f599c0: f2(3)> 1
<Greenlet at 0x2f598b0: f1(3)> 2
<Greenlet at 0x2f599c0: f2(3)> 2

打补丁:不替换sleep, socket.conn,socket.reciv...socket

因为切换是在IO操做时自动完成,因此gevent须要修改Python自带的一些标准库,这一过程在启动时经过monkey patch完成函数

from gevent import monkey

#打补丁,保证不用替换原来耗时操做的函数
monkey.patch_all()

join_all方法:性能

gevent.joinall([
        gevent.spawn(f1, 5),
        gevent.spawn(f2, 5)
    ])
#encoding:utf-8
# __author__ = 'donghao'
# __time__ = 2019/4/2 13:57
import gevent
import time
from gevent import monkey

#打补丁,保证不用替换原来耗时操做的函数
monkey.patch_all()

def f1(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        time.sleep(1)

def f2(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        time.sleep(1)

if __name__ == '__main__':
    gevent.joinall([
        gevent.spawn(f1, 5),
        gevent.spawn(f2, 5)
    ])
    # 至关于:
     # g1 = gevent.spawn(f1,5)
    # g2 = gevent.spawn(f2,5)
    # g1.join()
    # g2.join()  
    print('end of main')
>>>
<Greenlet at 0x39fc2d8: f1(5)> 0
<Greenlet at 0x39fc360: f2(5)> 0
<Greenlet at 0x39fc2d8: f1(5)> 1
<Greenlet at 0x39fc360: f2(5)> 1
<Greenlet at 0x39fc2d8: f1(5)> 2
<Greenlet at 0x39fc360: f2(5)> 2
<Greenlet at 0x39fc2d8: f1(5)> 3
<Greenlet at 0x39fc360: f2(5)> 3
<Greenlet at 0x39fc2d8: f1(5)> 4
<Greenlet at 0x39fc360: f2(5)> 4
end of main

因为gevent是基于IO切换的协程,因此最神奇的是,咱们编写的Web App代码,不须要引入gevent的包,也不须要改任何代码,仅仅在部署的时候,用一个支持geventWSGI服务器,马上就得到了数倍的性能提高spa

相关文章
相关标签/搜索