協程回顧

在這裏插入圖片描述
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

相關文章
相關標籤/搜索