立即學習:https://edu.csdn.net/course/play/24458/296457?utm_source=blogtoedu
協程(yield,greenlet,gevent)
?
1.協程:在單線程中通過不斷地在多個任務之間進行切換執行,來達到并發的效果的線程,可以提高效率
?
2.yield實現協程
#yield = return + generator(生成器)
#有yield的函數就是生成器,不會直接執行函數,首先獲得生成器對象然后使用next函數這才開始運行函數
#next方法#并發執行
import time
def productor():g = costumor()for i in range(100):res = next(g)print(res)def costumor():for i in range(100):res = yield "*"*5+"%s"%i+'*'*5if __name__ == '__main__':start_time = time.time()productor()end_time = time.time()print('%.9f'%float(end_time-start_time))#串行
def productor():res = costumor()for i in res:print('*'*5+str(i)+"*"*5)def costumor():res=[]for i in range(100):res.append(i)return resif __name__ == '__main__':start_time = time.time()productor()end_time = time.time()print('%.9f'%float(end_time-start_time))
?
3.greenlet實現協程
#greenlet也是i一個可以實現單線程內并發的效果,但是和yield一樣不能檢測i/o模型
#切換的格式為:
'''
g1 = greenlet(function1)#獲得對象
g2.switch(para)#從當前任務切換到g2對應的任務中
'''
#協程并發
from greenlet import greenlet#定義函數一
def eat(name):print('%s1 is eating'%name)g2.switch('同學')print('%s2 is eating'%name)g2.switch()#定義函數2
def play(name):print('%s1 is playing'%name)g1.switch()print('%s2 is playing'%name)if __name__ == '__main__':g1 = greenlet(eat)g2 = greenlet(play)g1.switch('同學')
?
4.gevent實現協程
#1.gevent模塊是基于greenlet模塊的,具有檢測自身I/O操作的功能
import gevent,time#定義任務1
def eat(name):print('%s eat 1'%name)#自身的I/O操作。可以被檢測出,一旦檢測出就自動進行任務·切換gevent.sleep(3)print('%s eat 2'%name)#定義任務2
def play(name):print('%s play 1'%name)gevent.sleep(4)print('%s play 2'%name)start_time = time.time()
#創建gevent對象,只是提交了任務,要想出結果,必須跟join函數配對使用
g1 = gevent.spawn(eat,'john')
g2 = gevent.spawn(play,'lucy')g1.join()
g2.join()
end_time = time.time()
print(end_time-start_time)
'''
運行結果:
john eat 1
lucy play 1
john eat 2
lucy play 2
4.0197389125823975#運行時間接近4秒,即兩個任務并發執行的#首先該程序是單線程,只有一個主線程,但是含有兩個任務,首先按照代碼從上到下執行,
執行到創建對象時,會自動跳轉到對應的函數中去,如g1跳到eat函數,執行第一次打印,
檢測到自身gevent.sleep()I/O操作后,就自動切換到下一個任務,執行play函數的第一次
打印,后面就是兩個任務均處于等待狀態,期間一直在兩個任務之間切換進行檢測,因為eat時間短,
所以先執行eat函數的第二次打印任務,接著就是Play的第二次打印#因此這里實現了單線程兩個任務并發的效果
'''#2.gevent模塊是基于greenlet模塊的,具有檢測自身I/O操作的功能,不能檢測自身以外的I/O操作,如time.sleep()
import gevent,time#定義任務1
def eat(name):print('%s eat 1'%name)#自身的I/O操作。可以被檢測出,一旦檢測出就自動進行任務·切換time.sleep(3)print('%s eat 2'%name)#定義任務2
def play(name):print('%s play 1'%name)time.sleep(4)print('%s play 2'%name)start_time = time.time()
#創建gevent對象,只是異步提交了任務,不會等結果的出來,要想出結果,必須跟join函數或者和joinall()配對使用,
g1 = gevent.spawn(eat,'john')
g2 = gevent.spawn(play,'lucy')g1.join()
g2.join()
#gevent.joinall([g1,g2])
end_time = time.time()
print(end_time-start_time)
'''
john eat 1
john eat 2
lucy play 1
lucy play 2
7.019653797149658
#運行時間接近與兩個任務I/O操作的時間總和,因此gevent不能檢測出自身以為的I/O操作
'''#3.gevent.monkey.patch_all():可以檢測到自身以外的I/O操作
import gevent,time
from gevent import monkey
monkey.patch_all()#定義任務1
def eat(name):print('%s eat 1'%name)#自身的I/O操作。可以被檢測出,一旦檢測出就自動進行任務·切換time.sleep(3)print('%s eat 2'%name)#定義任務2
def play(name):print('%s play 1'%name)time.sleep(4)print('%s play 2'%name)start_time = time.time()
#創建gevent對象,只是提交了任務,要想出結果,必須跟join函數配對使用
g1 = gevent.spawn(eat,'john')
g2 = gevent.spawn(play,'lucy')g1.join()
g2.join()
end_time = time.time()
print(end_time-start_time)
'''
john eat 1
lucy play 1
john eat 2
lucy play 2
4.009758949279785#說明檢測到了time.sleep()的I/O操作,自動進行切換,實現了單線程并發的效果
'''
?