摘要:所以在第一遍閱讀官方文檔的時候,感覺完全是在夢游。通過或者等待另一個協(xié)程的結果或者異常,異常會被傳播。接口返回的結果指示已結束,并賦值。取消與取消不同。調用將會向被包裝的協(xié)程拋出。任務相關函數安排協(xié)程的執(zhí)行。負責切換線程保存恢復。
Tasks and coroutines
翻譯的python官方文檔
這個問題的惡心之處在于,如果你要理解coroutine,你應該理解future和task。而你如果想理解future和task你應該先理解coroutine。所以在第一遍閱讀官方文檔的時候,感覺完全是在夢游。但讀到第二遍和第三遍的時候,就清楚很多了。
Coroutines協(xié)程(coroutine)包括兩個概念:
協(xié)程函數(async def 或者 @asyncio.coroutine)
協(xié)程函數所返回的協(xié)程對象。
協(xié)程功能:
通過result = await future或者 result = yeild from future,懸掛協(xié)程,直到future完成,獲取future的結果/異常(參見下面對future及future結果的描述,或等看完future之后回來再閱讀這一段)。
通過 result = await coroutine 或者 result = yeild from coroutine 等待另一個協(xié)程的結果(或者異常,異常會被傳播)。
returen expression 返回該協(xié)程的結果,被await,或者yield from獲取。
raise exception,拋出異常,被await,或者yield from獲取。
調用協(xié)程函數并不能使該協(xié)程運行。調用協(xié)程函數所返回的協(xié)程對象,在被你安排執(zhí)行之前,不會做任何事情。有兩種方式可以啟動它:
通過在一個已經啟動的協(xié)程中調用:await coroutine或者yield from coroutine
或者通過ensure_task()以及loop.create_task()安排協(xié)程的執(zhí)行。
只有事件循環(huán)在運行的時候,協(xié)程才能運行
在本文檔中,有些普通函數返回了一個future,也被標記為coroutine。這是故意的,這樣以后就可以自由使用這些函數。如果是在回調代碼中使用這個函數,用ensure_future包裝他。
hello_world.py
import asyncio # 創(chuàng)建一個協(xié)程 async def hello_world(): print("Hello World!") loop = asyncio.get_event_loop() # Blocking call which returns when the hello_world() coroutine is done # 在事件循環(huán)中調用這個協(xié)程 # 不過這里只有一個協(xié)程,而其不阻塞 loop.run_until_complete(hello_world()) loop.close()
hello_world2.py
# 這段代碼和上面的代碼執(zhí)行結果是相同的。只不過用了另一種調用協(xié)程的方式 # 先在loop.call_soon()中安排好,再通過loop.run_forever()調用 # 注意,這里在hello_world中,調用了loop.stop(),否則事件循環(huán)就不會終止。 import asyncio def hello_world(loop): print("Hello World") loop.stop() loop = asyncio.get_event_loop() # Schedule a call to hello_world() loop.call_soon(hello_world, loop) # Blocking call interrupted by loop.stop() loop.run_forever() loop.close()
注意這里return 1+2,實際上是raise StopIteration(3)協(xié)程其實是在不停返回結果的。最后的結果才會被返回。
futurefuture是一個容器,或者占位符(placeholder),用于接受異步的結果。這里指的是asyncio.Future而不是coroutines.futures.Future。
接口result()
返回future的結果
set_result()
指示future已結束,并賦值。注意,必須顯式地調用這個接口,才能給future賦值。
import asyncio # 一個對future進行賦值的函數 async def slow_operation(future): await asyncio.sleep(1) # 給future賦值 future.set_result("Future is done!") loop = asyncio.get_event_loop() # 創(chuàng)建一個future future1 = asyncio.Future() # 使用ensure_future 創(chuàng)建Task asyncio.ensure_future(slow_operation(future1)) future2 = asyncio.Future() asyncio.ensure_future(slow_operation(future2)) # gather Tasks,并通過run_uniti_complete來啟動、終止loop loop.run_until_complete(asyncio.gather(future1, future2)) print(future1.result()) print(future2.result()) loop.close()
如果我們注釋掉`future.set_result("Future is done!")一行,這個程序將永遠不會結束。
TASKSchedule the execution of a coroutine: wrap it in a future. Task is a subclass of Future.
將一個協(xié)程的執(zhí)行過程安排好:用一個future包裝起來。Task是Future的一個子類。
A task is responsible for executing a coroutine object in an event loop. If the wrapped coroutine yields from a future, the task suspends the execution of the wrapped coroutine and waits for the completion of the future. When the future is done, the execution of the wrapped coroutine restarts with the result or the exception of the future.
Task 負責在實現循環(huán)中執(zhí)行一個協(xié)程。 如果被包裝的協(xié)程由一個future產生,task會暫停被包裝協(xié)程的執(zhí)行,等待future的完成。當future完成時,被包裝協(xié)程會重啟,當future結果/異常返回。
Event loops use cooperative scheduling: an event loop only runs one task at a time. Other tasks may run in parallel if other event loops are running in different threads. While a task waits for the completion of a future, the event loop executes a new task.
事件循環(huán)使用協(xié)同調度:事件循環(huán)每次只能執(zhí)行1個操作。其他task可以在別的線程的事件循環(huán)中執(zhí)行。當task等待future完成時,事件循環(huán)會執(zhí)行一個新的task。
The cancellation of a task is different from the cancelation of a future. Calling cancel() will throw a CancelledError to the wrapped coroutine. cancelled() only returns True if the wrapped coroutine did not catch the CancelledError exception, or raised a CancelledError exception.
取消task與取消future不同。調用cancel()將會向被包裝的協(xié)程拋出CacelledError。如果被包裝協(xié)程沒有捕獲CacelledError或者拋出CancelledError時, cancelled()才返回True
這里可以參考Task源碼中的一段注釋:
Request that this task cancel itself.
This arranges for a CancelledError to be thrown into the wrapped coroutine on the next cycle through the event loop. The coroutine then has a chance to clean up or even deny the request using try/except/finally. Unlike Future.cancel, this does not guarantee that the task will be cancelled: the exception might be caught and acted upon, delaying cancellation of the task or preventing cancellation completely. The task may also return a value or raise a different exception. Immediately after this method is called, Task.cancelled() will not return True (unless the task was already cancelled). A task will be marked as cancelled when the wrapped coroutine terminates with a CancelledError exception (even if cancel() was not called)
太長了,我就不翻譯了大意就是說,雖然task的cancel()函數,只會向被包裝協(xié)程發(fā)出拋出一個異常,但是task是否真的canceled取決于被包裝協(xié)程如何處理這個異常。
不要直接創(chuàng)建task實例,使用ensure_future()函數或者loop.create_task()方法。
任務相關函數asyncio.ensure_future
安排協(xié)程的執(zhí)行。用future包裝它,返回一個task。
asyncio.gather(*coros_or_futures, loop=None, return_exceptions=False)
將多個協(xié)程或future,集成為一個future。 所有的future必須在一個事件循環(huán)中。如果所有的future都成功完成了,則按照輸入順序(而不是返回順序)返回所有result。
asyncio.sleep(delay, result=None, *, loop=None)
sleep函數,注意,是可以返回結果的
一些參考資料
awesome asyncio
參考這篇文章
線程是操作系統(tǒng)層面的“并行”, 協(xié)程是應用程序層面的“并行”。
協(xié)程本質上就是:提供一個環(huán)境,保存一些需要等待的任務,當這些任務可以執(zhí)行(等待結束)的時候,能夠執(zhí)行。再等待的過程中,程序可以執(zhí)行別的任務。
以下內容參考自:PYTHON: GENERATORS, COROUTINES, NATIVE COROUTINES AND ASYNC/AWAIT
@asyncio.coroutine def foo(): yield from ....
async def foo(): await ......
注意在@asyncio.coroutine里只能是 yield from, 在async中,只能是await。
你可以通過@type.coroutine裝飾器,降一個generator變?yōu)橐粋€可await得協(xié)程。
Asynchronous Python
多線程:創(chuàng)建多個線程,每個線程處理一個任務。會競爭資源、死鎖什么的。CPU負責切換線程、保存恢復context。
Asnycio的文檔,但是感覺寫的一般,有些語焉不詳。
引用了一片關于線程的文章,還沒看
不用gevent的原因,是因為gevent還是使用了線程,而線程是難以調試的。
Some thoughts on asynchronous API design in a post-async/await world
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/41135.html
摘要:主程序通過喚起子程序并傳入數據,子程序處理完后,用將自己掛起,并返回主程序,如此交替進行。通過輪詢或是等事件框架,捕獲返回的事件。從消息隊列中取出記錄,恢復協(xié)程函數。然而事實上只有直接操縱的協(xié)程函數才有可能接觸到這個對象。 首發(fā)于 我的博客 轉載請注明出處 寫在前面 本文默認讀者對 Python 生成器 有一定的了解,不了解者請移步至生成器 - 廖雪峰的官方網站。 本文基于 Pyth...
摘要:譯者說于年月日發(fā)布,該版本正式支持的關鍵字,并且用舊版本編譯同樣可以使用這兩個關鍵字,這無疑是一種進步。其次,這是最后一個支持和的版本了,在后續(xù)的版本了會移除對它們的兼容。 譯者說 Tornado 4.3于2015年11月6日發(fā)布,該版本正式支持Python3.5的async/await關鍵字,并且用舊版本CPython編譯Tornado同樣可以使用這兩個關鍵字,這無疑是一種進步。其次...
摘要:是之后引入的標準庫的,這個包使用事件循環(huán)驅動的協(xié)程實現并發(fā)。沒有能從外部終止線程,因為線程隨時可能被中斷。上一篇并發(fā)使用處理并發(fā)我們介紹過的,在中,只是調度執(zhí)行某物的結果。 asyncio asyncio 是Python3.4 之后引入的標準庫的,這個包使用事件循環(huán)驅動的協(xié)程實現并發(fā)。asyncio 包在引入標準庫之前代號 Tulip(郁金香),所以在網上搜索資料時,會經??吹竭@種花的...
閱讀 3532·2021-09-27 13:35
閱讀 3570·2019-08-29 17:09
閱讀 2450·2019-08-26 11:30
閱讀 711·2019-08-26 10:32
閱讀 545·2019-08-26 10:23
閱讀 1206·2019-08-26 10:20
閱讀 3160·2019-08-23 15:26
閱讀 3571·2019-08-23 14:33