摘要:所以在第一遍閱讀官方文檔的時候,感覺完全是在夢游。通過或者等待另一個協(xié)程的結(jié)果或者異常,異常會被傳播。接口返回的結(jié)果指示已結(jié)束,并賦值。取消與取消不同。調(diào)用將會向被包裝的協(xié)程拋出。任務(wù)相關(guān)函數(shù)安排協(xié)程的執(zhí)行。負(fù)責(zé)切換線程保存恢復(fù)。
Tasks and coroutines
翻譯的python官方文檔
這個問題的惡心之處在于,如果你要理解coroutine,你應(yīng)該理解future和task。而你如果想理解future和task你應(yīng)該先理解coroutine。所以在第一遍閱讀官方文檔的時候,感覺完全是在夢游。但讀到第二遍和第三遍的時候,就清楚很多了。
Coroutines協(xié)程(coroutine)包括兩個概念:
協(xié)程函數(shù)(async def 或者 @asyncio.coroutine)
協(xié)程函數(shù)所返回的協(xié)程對象。
協(xié)程功能:
通過result = await future或者 result = yeild from future,懸掛協(xié)程,直到future完成,獲取future的結(jié)果/異常(參見下面對future及future結(jié)果的描述,或等看完future之后回來再閱讀這一段)。
通過 result = await coroutine 或者 result = yeild from coroutine 等待另一個協(xié)程的結(jié)果(或者異常,異常會被傳播)。
returen expression 返回該協(xié)程的結(jié)果,被await,或者yield from獲取。
raise exception,拋出異常,被await,或者yield from獲取。
調(diào)用協(xié)程函數(shù)并不能使該協(xié)程運(yùn)行。調(diào)用協(xié)程函數(shù)所返回的協(xié)程對象,在被你安排執(zhí)行之前,不會做任何事情。有兩種方式可以啟動它:
通過在一個已經(jīng)啟動的協(xié)程中調(diào)用:await coroutine或者yield from coroutine
或者通過ensure_task()以及loop.create_task()安排協(xié)程的執(zhí)行。
只有事件循環(huán)在運(yùn)行的時候,協(xié)程才能運(yùn)行
在本文檔中,有些普通函數(shù)返回了一個future,也被標(biāo)記為coroutine。這是故意的,這樣以后就可以自由使用這些函數(shù)。如果是在回調(diào)代碼中使用這個函數(shù),用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)中調(diào)用這個協(xié)程 # 不過這里只有一個協(xié)程,而其不阻塞 loop.run_until_complete(hello_world()) loop.close()
hello_world2.py
# 這段代碼和上面的代碼執(zhí)行結(jié)果是相同的。只不過用了另一種調(diào)用協(xié)程的方式 # 先在loop.call_soon()中安排好,再通過loop.run_forever()調(diào)用 # 注意,這里在hello_world中,調(diào)用了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é)程其實是在不停返回結(jié)果的。最后的結(jié)果才會被返回。
futurefuture是一個容器,或者占位符(placeholder),用于接受異步的結(jié)果。這里指的是asyncio.Future而不是coroutines.futures.Future。
接口result()
返回future的結(jié)果
set_result()
指示future已結(jié)束,并賦值。注意,必須顯式地調(diào)用這個接口,才能給future賦值。
import asyncio # 一個對future進(jìn)行賦值的函數(shù) 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!")一行,這個程序?qū)⒂肋h(yuǎn)不會結(jié)束。
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 負(fù)責(zé)在實現(xiàn)循環(huán)中執(zhí)行一個協(xié)程。 如果被包裝的協(xié)程由一個future產(chǎn)生,task會暫停被包裝協(xié)程的執(zhí)行,等待future的完成。當(dāng)future完成時,被包裝協(xié)程會重啟,當(dāng)future結(jié)果/異常返回。
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é)同調(diào)度:事件循環(huán)每次只能執(zhí)行1個操作。其他task可以在別的線程的事件循環(huán)中執(zhí)行。當(dāng)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不同。調(diào)用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()函數(shù),只會向被包裝協(xié)程發(fā)出拋出一個異常,但是task是否真的canceled取決于被包裝協(xié)程如何處理這個異常。
不要直接創(chuàng)建task實例,使用ensure_future()函數(shù)或者loop.create_task()方法。
任務(wù)相關(guān)函數(shù)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函數(shù),注意,是可以返回結(jié)果的
一些參考資料
awesome asyncio
參考這篇文章
線程是操作系統(tǒng)層面的“并行”, 協(xié)程是應(yīng)用程序?qū)用娴摹安⑿小薄?/p>
協(xié)程本質(zhì)上就是:提供一個環(huán)境,保存一些需要等待的任務(wù),當(dāng)這些任務(wù)可以執(zhí)行(等待結(jié)束)的時候,能夠執(zhí)行。再等待的過程中,程序可以執(zhí)行別的任務(wù)。
以下內(nèi)容參考自: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)建多個線程,每個線程處理一個任務(wù)。會競爭資源、死鎖什么的。CPU負(fù)責(zé)切換線程、保存恢復(fù)context。
Asnycio的文檔,但是感覺寫的一般,有些語焉不詳。
引用了一片關(guān)于線程的文章,還沒看
不用gevent的原因,是因為gevent還是使用了線程,而線程是難以調(diào)試的。
Some thoughts on asynchronous API design in a post-async/await world
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/41135.html
摘要:主程序通過喚起子程序并傳入數(shù)據(jù),子程序處理完后,用將自己掛起,并返回主程序,如此交替進(jìn)行。通過輪詢或是等事件框架,捕獲返回的事件。從消息隊列中取出記錄,恢復(fù)協(xié)程函數(shù)。然而事實上只有直接操縱的協(xié)程函數(shù)才有可能接觸到這個對象。 首發(fā)于 我的博客 轉(zhuǎn)載請注明出處 寫在前面 本文默認(rèn)讀者對 Python 生成器 有一定的了解,不了解者請移步至生成器 - 廖雪峰的官方網(wǎng)站。 本文基于 Pyth...
摘要:譯者說于年月日發(fā)布,該版本正式支持的關(guān)鍵字,并且用舊版本編譯同樣可以使用這兩個關(guān)鍵字,這無疑是一種進(jìn)步。其次,這是最后一個支持和的版本了,在后續(xù)的版本了會移除對它們的兼容。 譯者說 Tornado 4.3于2015年11月6日發(fā)布,該版本正式支持Python3.5的async/await關(guān)鍵字,并且用舊版本CPython編譯Tornado同樣可以使用這兩個關(guān)鍵字,這無疑是一種進(jìn)步。其次...
摘要:是之后引入的標(biāo)準(zhǔn)庫的,這個包使用事件循環(huán)驅(qū)動的協(xié)程實現(xiàn)并發(fā)。沒有能從外部終止線程,因為線程隨時可能被中斷。上一篇并發(fā)使用處理并發(fā)我們介紹過的,在中,只是調(diào)度執(zhí)行某物的結(jié)果。 asyncio asyncio 是Python3.4 之后引入的標(biāo)準(zhǔn)庫的,這個包使用事件循環(huán)驅(qū)動的協(xié)程實現(xiàn)并發(fā)。asyncio 包在引入標(biāo)準(zhǔn)庫之前代號 Tulip(郁金香),所以在網(wǎng)上搜索資料時,會經(jīng)常看到這種花的...
閱讀 3657·2021-09-27 13:35
閱讀 3622·2019-08-29 17:09
閱讀 2517·2019-08-26 11:30
閱讀 761·2019-08-26 10:32
閱讀 610·2019-08-26 10:23
閱讀 1264·2019-08-26 10:20
閱讀 3221·2019-08-23 15:26
閱讀 3690·2019-08-23 14:33