《流利的Python》筆記 -- Coroutine

如果Python Books是一些指導(dǎo),那么皆愉,coroutines是最少被記載概作,晦澀的腋妙,看上去沒什么用的功能。 -- David Beazley讯榕, Python author

caller從generator中拉取數(shù)據(jù)骤素。

一個coroutine從結(jié)構(gòu)上像是一個generator匙睹,只是一個包含yield關(guān)鍵字的函數(shù)而已。

coroutine可以從caller中接收數(shù)據(jù)济竹,通過.send() 代替 .next()痕檬。甚至,yield關(guān)鍵字也可以沒有數(shù)據(jù)流入流出送浊。除了數(shù)據(jù)流梦谜,yield也是一個控制流程的設(shè)備,使多任務(wù)間協(xié)作袭景。(yield的本身意思就是“放棄”)每個coroutine yields 控制返還給scheduler唁桩,因此,其他的coroutine被激活耸棒。

當(dāng)你把yield主要想成流程控制的手段時(shí)朵夏,你就快理解coroutine了。

Python coroutine是一系列改進(jìn)簡陋的generator的成果榆纽。coroutine就是從PEP342中引入仰猖,即Coroutines via Enhandced Generators,Python2.5奈籽。通過send傳入數(shù)據(jù)饥侵,這讓generator可以被用作coroutine,一個協(xié)作的過程衣屏,yielding and receiving values from the caller躏升。

除了send,PEP 342還加入了throw和close狼忱,允許caller拋出異常膨疏,該異常在generator里面處理,也可以結(jié)束generator钻弄。PEP 380讓coroutine支持return和yield from佃却。

coroutine可以處于4種狀態(tài),通過inspect.getgeneratorstate()函數(shù)來確定狀態(tài):
1.GEN_CREATED窘俺,等待開始
2.GEN_RUNNING饲帅,被解釋器執(zhí)行
3.GEN_SUSPENED,在yield表達(dá)式處掛起
4.GEN_CLOSED瘤泪,執(zhí)行結(jié)束

caller通過send傳入coroutine的數(shù)據(jù)灶泵,會在yield處獲得,所以对途,coroutine必須處于yield出掛起時(shí)(GEN_SUSPENDED)赦邻,才能通過send傳入數(shù)據(jù)已卸。這也就解釋了烛芬,coroutine第一次被激活丁频,一定是通過next霞丧,否則處于GEN_CREADED狀態(tài)下,無法send湃鹊。初始的next調(diào)用儒喊,是為了讓coroutine準(zhǔn)備好镣奋。值得說的是币呵,如果coroutine中有這樣的表達(dá)式“b = yield a”,那么此處侨颈,caller是必須send一個值進(jìn)來余赢,也就是綁定給b的值,要不然b為None哈垢。

重要的一點(diǎn)妻柒,要理解為什么coroutine的執(zhí)行流程,會恰好在yield處掛起耘分,確切的說举塔,如果b = yield a,是在yield a掛起求泰,b =在下次執(zhí)行央渣。因?yàn)檫@個表達(dá)式“b = yield a”,只有在協(xié)程被客戶端激活之后渴频,b的值才能被設(shè)置芽丹。這對理解異步編程有用。

第一次調(diào)用next卜朗,讓coroutine處于第一個yield處掛起拔第,這個準(zhǔn)備過程叫做coroutine priming,為了更方便场钉,引入decorator蚊俺,@coroutine。

對于yield from逛万,在調(diào)用時(shí)自動prime協(xié)程春叫,所以,與yield from搭配的asyncio.coroutine泣港,其實(shí)沒有做prime工作暂殖。

終止協(xié)程和異常處理
協(xié)程內(nèi)一個未處理的異常會隨著send或next傳播到caller中。

generator.throw
導(dǎo)致generator被掛起的yield處当纱,拋出異常呛每。如果generator處理異常,則當(dāng)前yield為throw本身坡氯,next會繼續(xù)到下一個yield晨横。如果generator不處理異常洋腮,異常傳播給caller,狀態(tài)為GEN_CLOSED手形。

generator.close
導(dǎo)致generator被掛起的yield處啥供,拋出GeneratorExit異常,狀態(tài)為GEN_CLOSED库糠。close不會yield 值伙狐。

從coroutine中返回值
一些coroutine不會yield有趣的值,而是被設(shè)計(jì)成返回一個結(jié)果瞬欧,一個累積的最后結(jié)果贷屎。

在coroutine中的return value語句,value回作為StopIteration的值偷偷地傳回給caller艘虎。這是一個hack唉侄,但是又符合coroutine的行為:在exhausted時(shí)拋出StopIteration,我們不得不這樣去獲取coroutine的返回值:

try:
    r = coro.send(None)
except StopIteration as exc:
    r = exc.value

Ok野建,PEP380引入了yield from語法属划,它會自動地在內(nèi)部捕獲StopIteration。
PEP380的標(biāo)題是“Syntax for Delegating to a Subgenerator”候生。

yield from語法最主要的功能是同眯,打開一個雙向的通道,在外部的caller與內(nèi)部的subgenerator之間陶舞,我們可以send數(shù)據(jù)進(jìn)去嗽测,也可以yield數(shù)據(jù)回來,而不用寫異常處理代碼肿孵。來看3個名詞解釋:

delegating generator
The generator function that contain the yield from <iterable> expression唠粥。

subgenerator
The generator obtained from the <iterable> part of the yield from expression。

caller
PEP380 uses the term "caller" to refer to the client code that calls the delegating generator. Depending on the context, I use "client" instead of "caller", to distinguish from the delegating generator, which is also a "caller"(it calls the subgenerator).

While the delegating generator is suspended at yield from, the caller sends data directly to the subgenerator, which yields data back to the caller. thee delegating generator resumes when the subgenerator returns and the interpreter raise StopIteration with the returned value attached.

delegating generator看不到caller傳給subgenerator的值停做。

書中一個例子16-17非常好晤愧,結(jié)論:
如果一個subgenerator不曾終止,那么蛉腌,delegating generator就不會被激活官份,一直處于掛起狀態(tài),一直掛在yield from處烙丛。但是舅巷,程序仍會進(jìn)行,因?yàn)閥ield from返還控制權(quán)給client河咽,就想yield一樣钠右,只是有些任務(wù)處于未完成狀態(tài)。

one delegating generator uses yield from to call a subgenerator, which itself is a delegating generator calling another subgenerator with yield from, and so on. Eventually, this chain must end in a simple generator that use just yield, or a iterable object.

yield from must be driven by a client that calls next() or send().

"when the iterator is another generator, the effect is the same as if the body of the subgenerator were inlined at the point of the yield from expression. Furthermore, the subgenerator is allowed to execute a return statement with a value, and that value become the value of the yield from expression.

PEP380中關(guān)于yield from語法的六點(diǎn)說明:
1.any values that the subgenerator yields are passed directly to the caller of the delegating generator(i.e., the client code).
2.any values sent to the delegating generator using send() are passed directly to the subgenerator. If the sent value is None, the subgenerator's next() method is called. If the sent value is not none the subgenerator's send() method is called. If the call raise StopIteration, the delegating generator is resumed. Any other exception is propagated to the delegating generator.
3.return expr in a generator or a subgenerator causes StopIteration(expr) to be raised upon exit from the generator.
4.The value of the yield from expression is the first argument to the StopIteration exception raised by the subgenerator when it terminates.
5.Exceptions other than GeneratorExit thrown into the delegating generator are passed to the throw() method of the subgenerator. If the call raise StopIteration, the delegating generator is resumed. Any other exception is propagated to the delegating generator.
6.If a GeneratorExit exception is thrown into the delegating generator, or the close() method of the delegating generator is called, then the close() method of the subgenerator is called if it has one. If this call results in an exception, it is propagated to the delegating generator. Otherwise, GeneratorExit is raised in the delegating generator.

現(xiàn)實(shí)是復(fù)雜的忘蟹,因?yàn)槲覀冃枰幚砜蛻舳说膖hrow和close飒房。PEP380的偽代碼被作者給予高度評價(jià)搁凸,讀了三遍才明白。要好好讀這個代碼狠毯,因?yàn)榇蠖鄶?shù)的yield from例子都在asyncio中护糖,不是獨(dú)立的例子。

再強(qiáng)調(diào)一下嚼松,yield from是auto prime哦嫡良。

This is a form of multitasking: coroutines voluntarily and explicitly yield control to the central scheduler.

廣義協(xié)程vsAsyncio協(xié)程
a broad, informal definition of a coroutine: a generator function driven by a client sending it data through send() calls or yield from. This broad definition is the one used in PEP 342 -- Coroutines via Enhanced Generators and in most existing Python books.
the asyncio coroutine, a stricter definition: asyncio coroutines are (usually) decorated with an @asyncio.coroutine decorator, and they are always driven by yield from, not by calling send() directly on them. Of course, asyncio coroutines are driven by next() and send() under the covers, but in user code, we only use yield from to make them run.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市惜颇,隨后出現(xiàn)的幾起案子皆刺,更是在濱河造成了極大的恐慌少辣,老刑警劉巖凌摄,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異漓帅,居然都是意外死亡锨亏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門忙干,熙熙樓的掌柜王于貴愁眉苦臉地迎上來器予,“玉大人,你說我怎么就攤上這事捐迫∏瑁” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵施戴,是天一觀的道長反浓。 經(jīng)常有香客問我,道長赞哗,這世上最難降的妖魔是什么雷则? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮肪笋,結(jié)果婚禮上月劈,老公的妹妹穿的比我還像新娘。我一直安慰自己藤乙,他們只是感情好猜揪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坛梁,像睡著了一般而姐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上罚勾,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天毅人,我揣著相機(jī)與錄音吭狡,去河邊找鬼。 笑死丈莺,一個胖子當(dāng)著我的面吹牛划煮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缔俄,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼弛秋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了俐载?” 一聲冷哼從身側(cè)響起蟹略,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遏佣,沒想到半個月后挖炬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡状婶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年意敛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膛虫。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡草姻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出稍刀,到底是詐尸還是另有隱情撩独,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布账月,位于F島的核電站综膀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏捶障。R本人自食惡果不足惜僧须,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望项炼。 院中可真熱鬧担平,春花似錦、人聲如沸锭部。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拌禾。三九已至取胎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背闻蛀。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工匪傍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人觉痛。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓役衡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親薪棒。 傳聞我的和親對象是個殘疾皇子手蝎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容