Python 協程,python協程
如果 Python 書籍有一定的指導作用,那麼(協程就是)文檔最匱乏、最鮮為人知的 Python 特性,因此表面上看是最無用的特性。
——David Beazley
Python 圖書作者
字典為動詞“to yield”給出了兩個釋義:產出和讓步。對於 Python 產生器中的 yield 來說,這兩個含義都成立。yield item 這行代碼會產出一個值,提供給 next(...) 的調用方;此外,還會作出讓步,暫停執行產生器,讓調用方繼續工作,直到需要使用另一個值時再調用next()。調用方會從產生器中拉取值。
從句法上看,協程與產生器類似,都是定義體中包含 yield 關鍵字的函數。可是,在協程中,yield 通常出現在運算式的右邊(例如,datum = yield),可以產出值,也可以不產出——如果 yield關鍵字後面沒有運算式,那麼產生器產出 None。協程可能會從調用方接收資料,不過調用方把資料提供給協程使用的是 .send(datum) 方法,而不是 next(...) 函數。通常,調用方會把值推送給協程。
yield 關鍵字甚至還可以不接收或傳出資料。不管資料如何流動,yield 都是一種流程式控制制工具,使用它可以實現協作式多任務:協程可以把控制器讓步給中心發送器,從而啟用其他的協程。
從根本上把 yield 視作控制流程程的方式,這樣就好理解協程了。
產生器如何進化成協程
協程的底層架構在“PEP 342—Coroutines via EnhancedGenerators”(https://www.python.org/dev/peps/pep-0342/)中定義,並在Python 2.5(2006 年)實現了。自此之後,yield 關鍵字可以在運算式中使用,而且產生器 API 中增加了 .send(value) 方法。產生器的調用方可以使用 .send(...) 方法發送資料,發送的資料會成為產生器函數中 yield 運算式的值。因此,產生器可以作為協程使用。協程是指一個過程,這個過程與調用方協作,產出由調用方提供的值。
除了 .send(...) 方法,PEP 342 還添加了 .throw(...) 和 .close()方法:前者的作用是讓調用方拋出異常,在產生器中處理;後者的作用是終止產生器。
用作協程的產生器的基本行為
舉個