Python - 多任務:協程
-
-
-
- 并行 and 并發
- 協程
- yield 實作
- greenlet 實作
- gevent 實作
-
-
-
并行 and 并發
在多任務中,存在兩個概念:并發與并行。
其中并發是假的多任務:在一個時間段中有多個程式都處于運作狀态,且這幾個程式是在同一個處理機上運作的,但任一個時刻點上實際隻有一個程式在處理機上運作。在宏觀上是同時進行,但微觀上仍是順序執行,是以稱之為假的多任務。
而并行則是真的多任務:多個程式同時在多個處理機上運作,宏觀上同時進行,在微觀上仍然是同時進行的,是以是真的多任務
對于之前講過的多線程,根據具體運作環境的不同,它所屬情況也不同。例如在 Java 中多線程就是真的多任務,是并行計算,而在 Python 中,由于全局解釋器鎖的存在(GIL,Global Interpreter Lock),使得在同一程序内任何時刻僅有一個線程在執行,是以運作中是假的多任務。
-
協程
Python 中的協程仍然是假的多任務,本質是調用多個生成器的__next__()
方法,達到多個生成器交替運作的效果。
協程運作于單線程中,任務排程(切換執行任務)都相當于調用函數,是以耗費的資源非常的少。(多程序最耗費資源,多線程次之,協程最少)
下面看一下協程的實作方式。
-
yield 實作
實際上通過調用
實作協程,使得多個函數交替進行。__next__()
def task_1(): while True: print("1") yield def task_2(): while True: print("2") yield def main(): t1 = task_1() t2 = task_2() while True: next(t1) next(t2) main()
-
greenlet 實作
import greenlet def task_1(): while True: print("1") # 手動切換到 task_2 g2.switch() def task_2(): while True: print("2") # 手動切換到 task_1 g1.switch() g1 = greenlet(task_1) g2 = greenlet(task_2)
-
gevent 實作
from gevent import monkey
import gevent
# 協程 gevent 在延時(或執行耗時操作、阻塞)的時候會自動切換任務
# 協程就是利用 IO 等待時間執行其他任務
# 方法内部使用 gevent.sleep() 進行延時操作,但手動添加 sleep 不現實,
# 是以使用 monkey.patch_all() 自動将所有等待操作替換成 gevent.sleep()
monkey.patch_all()
def task_1():
while True:
print("1")
# 手動切換到 task_2
g2.switch()
def task_2():
while True:
print("2")
# 手動切換到 task_1
g1.switch()
g1 = gevent.spawn(task_1)
g2 = gevent.spawn(task_2)
# 或者 gevent.joinall([g1, g2])
g1.join()
g2.join()