摘要:協程定義協程是指一個過程,這個過程與調用方協作,產出由調用方提供的值。當得到控制權時,會阻塞,同時等待終止。終止協程的方法該方法致使生成器在暫停的表達式處拋出異常。
協程
定義:協程是指一個過程,這個過程與調用方協作,產出由調用方提供的值。(協程中必定含有一條yield語句)
協程與生成器類似,都是定義體內包含yield關鍵字的函數。不過,在協程中,yield通常出現在表達式的右邊(例如,data = yield),可以產出值,也可以不產出。
生成器不可以返回值,如果生成器中給return語句提供值,會拋出SyntaxError異常;
python新引入yield from 語句,可以把復雜的生成器重構成小型的嵌套生成器,省去了大量樣板代碼。
三個方法:. send() 方法,可以讓調用方給協程發送數據,發送的數據會成為協程函數中 yield 表達式的值。
.throw() 方法,可以讓調用方拋出異常
.close() 方法,可以讓調用方終止協程
四個狀態:"GEN_CREATED" 等待開始執行
"GEN_RUNNING" 解釋器正在執行
"GEN_SUSPENDED" 在yield表達式處暫停
"GEN_CLOASED" 執行結束
協程只能處于這四個狀態中的一個,當前狀態可以由 inspect.getgeneratorstate(...)函數獲取
因為send() 方法的參數會成為暫停的yield表達式的值,所以,僅當協程處于暫停狀態時才能調用send()方法
協程需要被預激,預激是通過next()函數進行
給協程添加預激裝飾器 functools.wraps(),可以省去協程的預激過程。
yield from在生成器gen中使用yield from subgen()時,subgen()會得到當前的控制權,把產出的值傳給gen的調用方,即調用方可以直接跳過gen控制subgen。當subgen得到控制權時,gen會阻塞,同時等待subgen終止。
一個小例子:
def chain(*iters): for iter in iters: yield from iter lst_1 = "abc" lst_2 = "987" print(list(chain(lst_1, lst_2)))
運行結果:
["a", "b", "c", "9", "8", "7"]
這個例子還可以改寫為:
def chain(): yield from "abc" yield from "987"
輸出結果是一樣的。
yield from 的主要功能是打開雙向通道,把最外層的調用方與最內層的子生成器連接起來,這樣,二者可以直接發送和產生值,甚至可以直接傳入異常。
一個復雜的例子,計算中學生的平均身高和體重:
from collections import namedtuple Result = namedtuple("Result", "count average") # 子生成器 def averager(): # <1> total = 0.0 count = 0 average = None while True: term = yield # <2> if term is None: # <3> break total += term count += 1 average = total/count return Result(count, average) # <4> # 委派生成器 def grouper(results, key): # <5> while True: # <6> results[key] = yield from averager() # <7> # 客戶端代碼,即調用端 def main(data): # <8> results = {} for key, values in data.items(): group = grouper(results, key) # <9> next(group) # <10> for value in values: group.send(value) # <11> group.send(None) # important! <12> # print(results) # uncomment to debug report(results) # 輸出報告 def report(results): for key, result in sorted(results.items()): group, unit = key.split(";") print("{:2} {:5} averaging {:.2f}{}".format( result.count, group, result.average, unit)) data = { "girls;kg": [40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5], "girls;m": [1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43], "boys;kg": [39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3], "boys;m": [1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46], } if __name__ == "__main__": main(data)
運行結果:
9 boys averaging 40.42kg 9 boys averaging 1.39m 10 girls averaging 42.04kg 10 girls averaging 1.43m
委派生成器grouper()只是起到一個傳輸數據的作用,沒有進行任何的數據處理。
生成器中都有一個無限循環 while True: 這個無限循環表明,只要調用方不斷把值發送給這個協程,它就會一直接收值,然后生成結果。該循環結束條件:
調用方在協程上顯式調用 .close() 方法,
或者沒有對協程的引用,而被垃圾回收程序回收時,這個協程才會終止。
終止協程的方法generator.close()
該方法致使生成器在暫停的 yield 表達式處拋出 GeneratorExit 異常。
如果生成器處理了這個異常,生成器一定不能產生值,否則解釋器會拋出RuntimeError異常。
如果生成器沒有處理這個異常,或者拋出StopIteration異常,即生成器已經運行到最后,調用方也不會報錯。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/42346.html
摘要:進程和線程究竟是什么東西傳統網絡服務模型是如何工作的協程和線程的關系和區別有哪些過程在什么時間發生在剛剛結束的上海站,來自七牛云存儲的高級工程師許智翔帶來了關于的分享中的進程線程協程同步異步回調。使用紅黑樹管理就緒隊列。 進程和線程究竟是什么東西?傳統網絡服務模型是如何工作的?協程和線程的關系和區別有哪些?IO過程在什么時間發生? 在剛剛結束的 PyCon2014 上海站,來自七牛云...
摘要:并發的方式有多種,多線程,多進程,異步等。多線程和多進程之間的場景切換和通訊代價很高,不適合密集型的場景關于多線程和多進程的特點已經超出本文討論的范疇,有興趣的同學可以自行搜索深入理解。 編程中,我們經常會遇到并發這個概念,目的是讓軟件能充分利用硬件資源,提高性能。并發的方式有多種,多線程,多進程,異步IO等。多線程和多進程更多應用于CPU密集型的場景,比如科學計算的時間都耗費在CPU...
摘要:當前狀態可以使用函數確定,該函數會返回下述字符串中的一個。解釋器正在執行。打印消息,然后協程終止,導致生成器對象拋出異常。實例運行完畢后,返回的值綁定到上。 協程 協程可以身處四個狀態中的一個。 當前狀態可以使用inspect.getgeneratorstate(...) 函數確定,該函數會返回下述字符串中的一個。 GEN_CREATED 等待開始執行。 GEN_RUNNING 解...
閱讀 1985·2021-11-23 10:03
閱讀 4189·2021-11-22 09:34
閱讀 2494·2021-10-08 10:05
閱讀 2257·2019-08-30 15:53
閱讀 1696·2019-08-30 13:56
閱讀 1165·2019-08-29 16:52
閱讀 1116·2019-08-26 13:31
閱讀 3356·2019-08-26 11:45