摘要:協程其實就是一個可中途中斷,由外部來控制執行進程的函數。這些第三方的選擇的共同特點是協程的都是隱式的。這就是顯示控制和隱式控制的區別。本文討論的協程就是這一種,后面會逐漸展開到如何利用這種顯示控制的協程來解決阻塞和流程阻塞的問題。
Python官方的實現里,協程只有generator這一招。協程其實就是一個可中途中斷,由外部來控制執行進程的函數。除了官方的generator,還有很多第三方的實現可以選擇。常見的第三方選擇有:
Greenlet,基于Python的常規版本(CPython)的C擴展實現
Stackless Python,是一個修改版本的Python解釋器,支持tasklet api
Pypy,是一個修改版本的Python解釋器,支持continulet api。它還基于此實現了模擬Greenlet和Stackless的上層api。
這些第三方的選擇的共同特點是協程的都是隱式的。比如,使用基于Greenlet的gevent,調用http api的時候,可能代碼寫起來是這樣的
urllib2.urlopen("http://www.google.com")
表面上看上去就是一個普通的函數調用,但是內部可能是
urlopen => http call => tcp socket open => create socket, register fd on event loop
最終在最內層,把當前的協程的控制權交出去了,讓event loop去回調當前的協程。也就是說urlopen這個函數調用可能導致當前執行的協程發生變化,而作為調用方可能根本不知情,除非你了解urlopen內層的所有實現,這就叫隱式的。
反觀generator,只要當前的語句沒有關鍵字“yield”,你就可以非常放心的認為當前這句話不會跳出當前協程,而會連續地執行下去。這個是一個優點,可以讓代碼變得更好理解,更不容易出因為執行順序不同修改共享狀態造成bug。但也是一個缺點,傳統的沒有yield的代碼是無法“自動”地“魔法般”地享受一些一步框架可能帶來的好處。比如說:
def process(): for i in sub_process(): yield i def sub_process(): yield 1 yield 2 yield 3 print(list(process()))
process不會因為調用了sub_process(),而sub_process()內又有yield就會自動交出當前協程的執行權,不會的。process如果想要交出執行權,必須自己再次yield。這就是顯示控制和隱式控制的區別。本文討論的協程就是generator這一種,后面會逐漸展開到如何利用這種顯示控制的協程來解決I/O阻塞和流程阻塞的logic locality問題。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/37379.html
摘要:比如里可以直接把執行權交給,而完全不知情。雖然不能和多線程相比,但是效果是類似的。對于多線程的代碼,是任何一行代碼都可能與其他線程并行。加上協程之間有共享狀態的話,一定程度上會產生類似多線程的并發讀寫狀態的。 前面講generator是顯式的協程的時候缺一個例子,現在補上 def parent_generator(): print(hello) yield from ...
摘要:如果說相比來說,是一種隱式的協程的話,提供的就更加隱式了。通過調用可以知道這個鏈表目前的大小。正式因為沒有把底層的協程直接控制接口開放,而是強買強賣了一個,所以想要在像那樣隨心所欲的操縱協程還是頗費一番周折的。 如果說greenlet相比generator來說,是一種隱式的協程的話,stackless python提供的api就更加隱式了。 import stackless def...
摘要:協程的基本行為協程包含四種狀態等待開始執行。協程中重要的兩個方法調用方把數據提供給協程。注意使用調用協程時會自動預激,因此與裝飾器不兼容標準庫中的裝飾器不會預激協程,因此能兼容句法。因此,終止協程的本質在于向協程發送其無法處理的異常。 導語:本文章記錄了本人在學習Python基礎之控制流程篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。 本文重點: 1、掌握協...
摘要:常規版本的的是不可以被持久化保存的。在流程被阻塞的時候比如需要審批老板不在把協程持久化成入庫,等流程不再阻塞的時候把協程重新從數據庫里拉起來繼續執行。 常規版本的Python的generator是不可以被持久化保存的。但是stackless和pypy這兩個修改版本的Python解釋器可以。下面這段代碼演示了如何把一個執行中的函數持久化保存,然后過段時間再把函數從上次執行到的地方原樣拉起...
閱讀 1019·2022-07-19 10:19
閱讀 1794·2021-09-02 15:15
閱讀 1007·2019-08-30 15:53
閱讀 2653·2019-08-30 13:45
閱讀 2651·2019-08-26 13:57
閱讀 1983·2019-08-26 12:13
閱讀 1006·2019-08-26 10:55
閱讀 545·2019-08-26 10:46