協程,又稱微線程,纖程。協程是Python中另外一種實現多任務的方式, 是比線程佔用更小的執行單元。
多進程, 多線程, 協程中差異見: 【Python面試場景】進程-線程-協程相關問題彙總
gevent是一個強大的並且能夠自動切換任務的模塊, 是Python的第三方庫, 需要單獨安裝。它使用 greenlet在libev 或libuv事件循環的頂部提供高級同步API 。
pip3 install gevent
其原理是當一個greenlet遇到IO(指的是input output 輸入輸出,比如網絡、文件操作等)操作時,比如訪問網絡,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。
由於IO操作非常耗時,經常使程序處於等待狀態,有了gevent爲我們自動切換協程,就保證總有greenlet在運行,而不是等待IO
1 使用
該案例中並沒有切換執行
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()
2 切換執行
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 打補丁 Monkey
from gevent import monkey
import gevent
import random
import time
# 有耗時操作時需要
monkey.patch_all() # 將程序中用到的耗時操作的代碼,換爲gevent中自己實現的模塊
def coroutine_work(coroutine_name):
for i in range(10):
print(coroutine_name, i)
time.sleep(random.random())
gevent.joinall([
gevent.spawn(coroutine_work, "work1"),
gevent.spawn(coroutine_work, "work2")
])
4 【多任務案例】併發下載器
from gevent import monkey
import gevent
import urllib.request
#有IO才做時需要這一句
monkey.patch_all()
def my_downLoad(file_name, url):
print('GET: %s' % url)
resp = urllib.request.urlopen(url)
data = resp.read()
with open(file_name, "wb") as f:
f.write(data)
print('%d bytes received from %s.' % (len(data), url))
gevent.joinall([
gevent.spawn(my_downLoad, "1.mp4", 'http://***.***.com/***.mp4'),
gevent.spawn(my_downLoad, "2.mp4", 'http://***.***.com/***.mp4'),
])
更多官方案例 https://github.com/gevent/gevent/blob/master/examples/