事件循環(huán)?
源代碼: Lib/asyncio/events.py, Lib/asyncio/base_events.py
前言
事件循環(huán)是每個(gè) asyncio 應(yīng)用的核心。 事件循環(huán)會(huì)運(yùn)行異步任務(wù)和回調(diào),執(zhí)行網(wǎng)絡(luò) IO 操作,以及運(yùn)行子進(jìn)程。
應(yīng)用開(kāi)發(fā)者通常應(yīng)當(dāng)使用高層級(jí)的 asyncio 函數(shù),例如 asyncio.run(),應(yīng)當(dāng)很少有必要引用循環(huán)對(duì)象或調(diào)用其方法。 本節(jié)所針對(duì)的主要是低層級(jí)代碼、庫(kù)和框架的編寫(xiě)者,他們需要更細(xì)致地控制事件循環(huán)行為。
獲取事件循環(huán)
以下低層級(jí)函數(shù)可被用于獲取、設(shè)置或創(chuàng)建事件循環(huán):
- asyncio.get_running_loop()?
返回當(dāng)前 OS 線(xiàn)程中正在運(yùn)行的事件循環(huán)。
如果沒(méi)有正在運(yùn)行的事件循環(huán)則會(huì)引發(fā)
RuntimeError。 此函數(shù)只能由協(xié)程或回調(diào)來(lái)調(diào)用。3.7 新版功能.
- asyncio.get_event_loop()?
獲取當(dāng)前事件循環(huán)。
如果當(dāng)前 OS 線(xiàn)程沒(méi)有設(shè)置當(dāng)前事件循環(huán),該 OS 線(xiàn)程為主線(xiàn)程,并且
set_event_loop()還沒(méi)有被調(diào)用,則 asyncio 將創(chuàng)建一個(gè)新的事件循環(huán)并將其設(shè)為當(dāng)前事件循環(huán)。由于此函數(shù)具有相當(dāng)復(fù)雜的行為(特別是在使用了自定義事件循環(huán)策略的時(shí)候),更推薦在協(xié)程和回調(diào)中使用
get_running_loop()函數(shù)而非get_event_loop()。應(yīng)該考慮使用
asyncio.run()函數(shù)而非使用低層級(jí)函數(shù)來(lái)手動(dòng)創(chuàng)建和關(guān)閉事件循環(huán)。3.10 版后已移除: 如果沒(méi)有正在運(yùn)行的事件循環(huán)則會(huì)發(fā)出棄用警告。 在未來(lái)的 Python 發(fā)行版中,此函數(shù)將成為
get_running_loop()的別名。
- asyncio.set_event_loop(loop)?
將 loop 設(shè)置為當(dāng)前 OS 線(xiàn)程的當(dāng)前事件循環(huán)。
- asyncio.new_event_loop()?
Create and return a new event loop object.
請(qǐng)注意 get_event_loop(), set_event_loop() 以及 new_event_loop() 函數(shù)的行為可以通過(guò) 設(shè)置自定義事件循環(huán)策略 來(lái)改變。
目錄
本文檔包含下列小節(jié):
事件循環(huán)方法集 章節(jié)是事件循環(huán)APIs的參考文檔;
回調(diào)處理 章節(jié)是從調(diào)度方法 例如
loop.call_soon()和loop.call_later()中返回Handle和TimerHandle實(shí)例的文檔。Server Objects 章節(jié)記錄了從事件循環(huán)方法返回的類(lèi)型,比如
loop.create_server();Event Loop Implementations 章節(jié)記錄了
SelectorEventLoop和ProactorEventLoop類(lèi);Examples 章節(jié)展示了如何使用某些事件循環(huán)API。
事件循環(huán)方法集?
事件循環(huán)有下列 低級(jí) APIs:
運(yùn)行和停止循環(huán)?
- loop.run_until_complete(future)?
運(yùn)行直到 future (
Future的實(shí)例 ) 被完成。如果參數(shù)是 coroutine object ,將被隱式調(diào)度為
asyncio.Task來(lái)運(yùn)行。返回 Future 的結(jié)果 或者引發(fā)相關(guān)異常。
- loop.run_forever()?
運(yùn)行事件循環(huán)直到
stop()被調(diào)用。如果
stop()在調(diào)用run_forever()之前被調(diào)用,循環(huán)將輪詢(xún)一次 I/O 選擇器并設(shè)置超時(shí)為零,再運(yùn)行所有已加入計(jì)劃任務(wù)的回調(diào)來(lái)響應(yīng) I/O 事件(以及已加入計(jì)劃任務(wù)的事件),然后退出。如果
stop()在run_forever()運(yùn)行期間被調(diào)用,循環(huán)將運(yùn)行當(dāng)前批次的回調(diào)然后退出。 請(qǐng)注意在此情況下由回調(diào)加入計(jì)劃任務(wù)的新回調(diào)將不會(huì)運(yùn)行;它們將會(huì)在下次run_forever()或run_until_complete()被調(diào)用時(shí)運(yùn)行。
- loop.stop()?
停止事件循環(huán)。
- loop.is_running()?
返回
True如果事件循環(huán)當(dāng)前正在運(yùn)行。
- loop.is_closed()?
如果事件循環(huán)已經(jīng)被關(guān)閉,返回
True。
- loop.close()?
關(guān)閉事件循環(huán)。
當(dāng)這個(gè)函數(shù)被調(diào)用的時(shí)候,循環(huán)必須處于非運(yùn)行狀態(tài)。pending狀態(tài)的回調(diào)將被丟棄。
此方法清除所有的隊(duì)列并立即關(guān)閉執(zhí)行器,不會(huì)等待執(zhí)行器完成。
這個(gè)方法是冪等的和不可逆的。事件循環(huán)關(guān)閉后,不應(yīng)調(diào)用其他方法。
- coroutine loop.shutdown_asyncgens()?
安排所有當(dāng)前打開(kāi)的 asynchronous generator 對(duì)象通過(guò)
aclose()調(diào)用來(lái)關(guān)閉。 在調(diào)用此方法后,如果有新的異步生成器被迭代事件循環(huán)將會(huì)發(fā)出警告。 這應(yīng)當(dāng)被用來(lái)可靠地完成所有已加入計(jì)劃任務(wù)的異步生成器。請(qǐng)注意當(dāng)使用
asyncio.run()時(shí)不必調(diào)用此函數(shù)。示例:
try: loop.run_forever() finally: loop.run_until_complete(loop.shutdown_asyncgens()) loop.close()
3.6 新版功能.
- coroutine loop.shutdown_default_executor()?
安排默認(rèn)執(zhí)行器的關(guān)閉并等待它合并
ThreadPoolExecutor中的所有線(xiàn)程。 在調(diào)用此方法后,如果在使用默認(rèn)執(zhí)行器期間調(diào)用了loop.run_in_executor()則將會(huì)引發(fā)RuntimeError。請(qǐng)注意當(dāng)使用
asyncio.run()時(shí)不必調(diào)用此函數(shù)。3.9 新版功能.
安排回調(diào)?
- loop.call_soon(callback, *args, context=None)?
安排 callback callback 在事件循環(huán)的下一次迭代時(shí)附帶 args 參數(shù)被調(diào)用。
回調(diào)按其注冊(cè)順序被調(diào)用。每個(gè)回調(diào)僅被調(diào)用一次。
可選鍵值類(lèi)的參數(shù) context 允許 callback 運(yùn)行在一個(gè)指定的自定義
contextvars.Context對(duì)象中。如果沒(méi)有提供 context ,則使用當(dāng)前上下文。返回一個(gè)能用來(lái)取消回調(diào)的
asyncio.Handle實(shí)例。這個(gè)方法不是線(xiàn)程安全的。
- loop.call_soon_threadsafe(callback, *args, context=None)?
call_soon()的線(xiàn)程安全變體。必須被用于安排 來(lái)自其他線(xiàn)程 的回調(diào)。如果在已被關(guān)閉的循環(huán)上調(diào)用則會(huì)引發(fā)
RuntimeError。 這可能會(huì)在主應(yīng)用程序被關(guān)閉時(shí)在二級(jí)線(xiàn)程上發(fā)生。參見(jiàn) concurrency and multithreading 部分的文檔。
在 3.7 版更改: 加入鍵值類(lèi)形參 context。請(qǐng)參閱 PEP 567 查看更多細(xì)節(jié)。
備注
大多數(shù) asyncio 的調(diào)度函數(shù)不讓傳遞關(guān)鍵字參數(shù)。為此,請(qǐng)使用 functools.partial() :
# will schedule "print("Hello", flush=True)"
loop.call_soon(
functools.partial(print, "Hello", flush=True))
使用 partial 對(duì)象通常比使用lambda更方便,asyncio 在調(diào)試和錯(cuò)誤消息中能更好的呈現(xiàn) partial 對(duì)象。
調(diào)度延遲回調(diào)?
事件循環(huán)提供安排調(diào)度函數(shù)在將來(lái)某個(gè)時(shí)刻調(diào)用的機(jī)制。事件循環(huán)使用單調(diào)時(shí)鐘來(lái)跟蹤時(shí)間。
- loop.call_later(delay, callback, *args, context=None)?
安排 callback 在給定的 delay 秒(可以是 int 或者 float)后被調(diào)用。
返回一個(gè)
asyncio.TimerHandle實(shí)例,該實(shí)例能用于取消回調(diào)。callback 只被調(diào)用一次。如果兩個(gè)回調(diào)被安排在同樣的時(shí)間點(diǎn),執(zhí)行順序未限定。
可選的位置參數(shù) args 在被調(diào)用的時(shí)候傳遞給 callback 。 如果你想把關(guān)鍵字參數(shù)傳遞給 callback ,請(qǐng)使用
functools.partial()。可選鍵值類(lèi)的參數(shù) context 允許 callback 運(yùn)行在一個(gè)指定的自定義
contextvars.Context對(duì)象中。如果沒(méi)有提供 context ,則使用當(dāng)前上下文。在 3.7 版更改: 加入鍵值類(lèi)形參 context。請(qǐng)參閱 PEP 567 查看更多細(xì)節(jié)。
在 3.8 版更改: 在 Python 3.7 和更早版本的默認(rèn)事件循環(huán)實(shí)現(xiàn)中, delay 不能超過(guò)一天。 這在 Python 3.8 中已被修復(fù)。
- loop.call_at(when, callback, *args, context=None)?
安排 callback 在給定的絕對(duì)時(shí)間戳 when (int 或 float) 被調(diào)用,使用與
loop.time()同樣的時(shí)間參考。本方法的行為和
call_later()方法相同。返回一個(gè)
asyncio.TimerHandle實(shí)例,該實(shí)例能用于取消回調(diào)。在 3.7 版更改: 加入鍵值類(lèi)形參 context。請(qǐng)參閱 PEP 567 查看更多細(xì)節(jié)。
在 3.8 版更改: 在 Python 3.7 和更早版本的默認(rèn)事件循環(huán)實(shí)現(xiàn)中,when 和當(dāng)前時(shí)間相差不能超過(guò)一天。 在這 Python 3.8 中已被修復(fù)。
備注
在 3.8 版更改: 在 Python 3.7 和更早版本中超時(shí) (相對(duì)的 delay 或絕對(duì)的 when) 不能超過(guò)一天。 這在 Python 3.8 中已被修復(fù)。
參見(jiàn)
asyncio.sleep() 函數(shù)。
創(chuàng)建 Future 和 Task?
- loop.create_future()?
創(chuàng)建一個(gè)附加到事件循環(huán)中的
asyncio.Future對(duì)象。這是在asyncio中創(chuàng)建Futures的首選方式。這讓第三方事件循環(huán)可以提供Future 對(duì)象的替代實(shí)現(xiàn)(更好的性能或者功能)。
3.5.2 新版功能.
- loop.create_task(coro, *, name=None, context=None)?
安排一個(gè) 協(xié)程 的執(zhí)行。返回一個(gè)
Task對(duì)象。第三方的事件循環(huán)可以使用它們自己的
Task子類(lèi)來(lái)滿(mǎn)足互操作性。這種情況下結(jié)果類(lèi)型是一個(gè)Task的子類(lèi)。如果提供了 name 參數(shù)且不為
None,它會(huì)使用Task.set_name()來(lái)設(shè)為任務(wù)的名稱(chēng)。An optional keyword-only context argument allows specifying a custom
contextvars.Contextfor the coro to run in. The current context copy is created when no context is provided.在 3.8 版更改: Added the name parameter.
在 3.11 版更改: Added the context parameter.
- loop.set_task_factory(factory)?
設(shè)置一個(gè)任務(wù)工廠,它將由
loop.create_task()來(lái)使用。If factory is
Nonethe default task factory will be set. Otherwise, factory must be a callable with the signature matching(loop, coro, context=None), where loop is a reference to the active event loop, and coro is a coroutine object. The callable must return aasyncio.Future-compatible object.
- loop.get_task_factory()?
返回一個(gè)任務(wù)工廠,或者如果是使用默認(rèn)值則返回
None。
打開(kāi)網(wǎng)絡(luò)連接?
- coroutine loop.create_connection(protocol_factory, host=None, port=None, *, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, happy_eyeballs_delay=None, interleave=None)?
打開(kāi)一個(gè)流式傳輸連接,連接到由 host 和 port 指定的地址。
套接字族可以是
AF_INET或AF_INET6,具體取決于 host (或 family 參數(shù),如果有提供的話(huà))。套接字類(lèi)型將為
SOCK_STREAM。protocol_factory 必須為一個(gè)返回 asyncio 協(xié)議 實(shí)現(xiàn)的可調(diào)用對(duì)象。
這個(gè)方法會(huì)嘗試在后臺(tái)創(chuàng)建連接。當(dāng)創(chuàng)建成功,返回
(transport, protocol)組合。底層操作的大致的執(zhí)行順序是這樣的:
創(chuàng)建連接并為其創(chuàng)建一個(gè) 傳輸。
不帶參數(shù)地調(diào)用 protocol_factory 并預(yù)期返回一個(gè) 協(xié)議 實(shí)例。
協(xié)議實(shí)例通過(guò)調(diào)用其
connection_made()方法與傳輸進(jìn)行配對(duì)。成功時(shí)返回一個(gè)
(transport, protocol)元組。
創(chuàng)建的傳輸是一個(gè)具體實(shí)現(xiàn)相關(guān)的雙向流。
其他參數(shù):
ssl: 如果給定該參數(shù)且不為假值,則會(huì)創(chuàng)建一個(gè) SSL/TLS 傳輸(默認(rèn)創(chuàng)建一個(gè)純 TCP 傳輸)。 如果 ssl 是一個(gè)
ssl.SSLContext對(duì)象,則會(huì)使用此上下文來(lái)創(chuàng)建傳輸對(duì)象;如果 ssl 為True,則會(huì)使用從ssl.create_default_context()返回的默認(rèn)上下文。參見(jiàn)
server_hostname 設(shè)置或重載目標(biāo)服務(wù)器的證書(shū)將要匹配的主機(jī)名。 應(yīng)當(dāng)只在 ssl 不為
None時(shí)傳入。 默認(rèn)情況下會(huì)使用 host 參數(shù)的值。 如果 host 為空那就沒(méi)有默認(rèn)值,你必須為 server_hostname 傳入一個(gè)值。 如果 server_hostname 為空字符串,則主機(jī)名匹配會(huì)被禁用(這是一個(gè)嚴(yán)重的安全風(fēng)險(xiǎn),使得潛在的中間人攻擊成為可能)。family, proto, flags 是可選的地址族、協(xié)議和標(biāo)志,它們會(huì)被傳遞給 getaddrinfo() 來(lái)對(duì) host 進(jìn)行解析。如果要指定的話(huà),這些都應(yīng)該是來(lái)自于
socket模塊的對(duì)應(yīng)常量。如果給出 happy_eyeballs_delay,它將為此鏈接啟用 Happy Eyeballs。 該函數(shù)應(yīng)當(dāng)為一個(gè)表示在開(kāi)始下一個(gè)并行嘗試之前要等待連接嘗試完成的秒數(shù)的浮點(diǎn)數(shù)。 這也就是在 RFC 8305 中定義的 "連接嘗試延遲"。 該 RFC 所推薦的合理默認(rèn)值為
0.25(250 毫秒)。interleave 控制當(dāng)主機(jī)名解析為多個(gè) IP 地址時(shí)的地址重排序。 如果該參數(shù)為
0或未指定,則不會(huì)進(jìn)行重排序,這些地址會(huì)按getaddrinfo()所返回的順序進(jìn)行嘗試。 如果指定了一個(gè)正整數(shù),這些地址會(huì)按地址族交錯(cuò)排列,而指定的整數(shù)會(huì)被解讀為 RFC 8305 所定義的 "首個(gè)地址族計(jì)數(shù)"。 如果 happy_eyeballs_delay 未指定則默認(rèn)值為0,否則為1。如果給出 sock,它應(yīng)當(dāng)是一個(gè)已存在、已連接并將被傳輸所使用的
socket.socket對(duì)象。 如果給出了 sock,則 host, port, family, proto, flags, happy_eyeballs_delay, interleave 和 local_addr 都不應(yīng)當(dāng)被指定。如果給出 local_addr,它應(yīng)當(dāng)是一個(gè)用來(lái)在本地綁定套接字的
(local_host, local_port)元組。 local_host 和 local_port 會(huì)使用getaddrinfo()來(lái)查找,這與 host 和 port 類(lèi)似。ssl_handshake_timeout 是(用于 TLS 連接的)在放棄連接之前要等待 TLS 握手完成的秒數(shù)。 如果參數(shù)為
None則使用 (默認(rèn)的)60.0。ssl_shutdown_timeout is the time in seconds to wait for the SSL shutdown to complete before aborting the connection.
30.0seconds ifNone(default).
在 3.5 版更改:
ProactorEventLoop類(lèi)中添加 SSL/TLS 支持。在 3.6 版更改: 套接字選項(xiàng)
TCP_NODELAY默認(rèn)已為所有 TCP 連接進(jìn)行了設(shè)置。在 3.7 版更改: Added the ssl_handshake_timeout parameter.
在 3.8 版更改: 增加了 happy_eyeballs_delay 和 interleave 形參。
Happy Eyeballs 算法:成功使用雙棧主機(jī)。 當(dāng)服務(wù)器的 IPv4 路徑和協(xié)議工作正常,但服務(wù)器的 IPv6 路徑和協(xié)議工作不正常時(shí),雙??蛻?hù)端應(yīng)用程序相比單獨(dú) IPv4 客戶(hù)端會(huì)感受到明顯的連接延遲。 這是不可接受的因?yàn)樗鼤?huì)導(dǎo)致雙??蛻?hù)端糟糕的用戶(hù)體驗(yàn)。 此文檔指明了減少這種用戶(hù)可見(jiàn)延遲的算法要求并提供了具體的算法。
詳情參見(jiàn): https://tools.ietf.org/html/rfc6555
在 3.11 版更改: Added the ssl_shutdown_timeout parameter.
參見(jiàn)
open_connection()函數(shù)是一個(gè)高層級(jí)的替代 API。 它返回一對(duì) (StreamReader,StreamWriter),可在 async/await 代碼中直接使用。
- coroutine loop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, *, family=0, proto=0, flags=0, reuse_port=None, allow_broadcast=None, sock=None)?
創(chuàng)建一個(gè)數(shù)據(jù)報(bào)連接。
套接字族可以是
AF_INET,AF_INET6或AF_UNIX,具體取決于 host (或 family 參數(shù),如果有提供的話(huà))。socket類(lèi)型將是
SOCK_DGRAM。protocol_factory 必須為一個(gè)返回 協(xié)議 實(shí)現(xiàn)的可調(diào)用對(duì)象。
成功時(shí)返回一個(gè)
(transport, protocol)元組。其他參數(shù):
如果給出 local_addr,它應(yīng)當(dāng)是一個(gè)用來(lái)在本地綁定套接字的
(local_host, local_port)元組。 local_host 和 local_port 是使用getaddrinfo()來(lái)查找的。remote_addr,如果指定的話(huà),就是一個(gè)
(remote_host, remote_port)元組,用于同一個(gè)遠(yuǎn)程地址連接。remote_host 和 remote_port 是使用getaddrinfo()來(lái)查找的。family, proto, flags 是可選的地址族,協(xié)議和標(biāo)志,其會(huì)被傳遞給
getaddrinfo()來(lái)完成 host 的解析。如果要指定的話(huà),這些都應(yīng)該是來(lái)自于socket模塊的對(duì)應(yīng)常量。reuse_port 告知內(nèi)核,只要在創(chuàng)建時(shí)都設(shè)置了這個(gè)旗標(biāo),就允許此端點(diǎn)綁定到其他現(xiàn)有端點(diǎn)所綁定的相同端口上。 這個(gè)選項(xiàng)在 Windows 和某些 Unix 上不受支持。 如果
SO_REUSEPORT常量未定義則此功能就是不受支持的。allow_broadcast 告知內(nèi)核允許此端點(diǎn)向廣播地址發(fā)送消息。
sock 可選擇通過(guò)指定此值用于使用一個(gè)預(yù)先存在的,已經(jīng)處于連接狀態(tài)的
socket.socket對(duì)象,并將其提供給此傳輸對(duì)象使用。如果指定了這個(gè)值, local_addr 和 remote_addr 就應(yīng)該被忽略 (必須為None)。
參見(jiàn) UDP echo 客戶(hù)端協(xié)議 和 UDP echo 服務(wù)端協(xié)議 的例子。
在 3.4.4 版更改: The family, proto, flags, reuse_address, reuse_port, allow_broadcast, and sock parameters were added.
在 3.8.1 版更改: The reuse_address parameter is no longer supported, as using
SO_REUSEADDRposes a significant security concern for UDP. Explicitly passingreuse_address=Truewill raise an exception.當(dāng)具有不同 UID 的多個(gè)進(jìn)程將套接字賦給具有
SO_REUSEADDR的相同 UDP 套接字地址時(shí),傳入的數(shù)據(jù)包可能會(huì)在套接字間隨機(jī)分配。對(duì)于受支持的平臺(tái),reuse_port 可以被用作類(lèi)似功能的替代。 通過(guò) reuse_port 將改用
SO_REUSEPORT,它能夠防止具有不同 UID 的進(jìn)程將套接字賦給相同的套接字地址。在 3.8 版更改: 添加WIndows的支持。
在 3.11 版更改: The reuse_address parameter, disabled since Python 3.9.0, 3.8.1, 3.7.6 and 3.6.10, has been entirely removed.
- coroutine loop.create_unix_connection(protocol_factory, path=None, *, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None)?
創(chuàng)建Unix 連接
套接字族將為
AF_UNIX;套接字類(lèi)型將為SOCK_STREAM。成功時(shí)返回一個(gè)
(transport, protocol)元組。path 是所要求的 Unix 域套接字的名字,除非指定了 sock 形參。 抽象的 Unix 套接字,
str,bytes和Path路徑都是受支持的。請(qǐng)查看
loop.create_connection()方法的文檔了解有關(guān)此方法的參數(shù)的信息。可用性: Unix。
在 3.7 版更改: Added the ssl_handshake_timeout parameter. The path parameter can now be a path-like object.
在 3.11 版更改: Added the ssl_shutdown_timeout parameter.
創(chuàng)建網(wǎng)絡(luò)服務(wù)?
- coroutine loop.create_server(protocol_factory, host=None, port=None, *, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, start_serving=True)?
創(chuàng)建TCP服務(wù) (socket 類(lèi)型
SOCK_STREAM) 監(jiān)聽(tīng) host 地址的 port 端口。返回一個(gè)
Server對(duì)象。參數(shù):
protocol_factory 必須為一個(gè)返回 協(xié)議 實(shí)現(xiàn)的可調(diào)用對(duì)象。
host 形參可被設(shè)為幾種類(lèi)型,它確定了服務(wù)器所應(yīng)監(jiān)聽(tīng)的位置:
如果 host 是一個(gè)字符串,則 TCP 服務(wù)器會(huì)被綁定到 host 所指明的單一網(wǎng)絡(luò)接口。
如果 host 是一個(gè)字符串序列,則 TCP 服務(wù)器會(huì)被綁定到序列所指明的所有網(wǎng)絡(luò)接口。
如果 host 是一個(gè)空字符串或
None,則會(huì)應(yīng)用所有接口并將返回包含多個(gè)套接字的列表(通常是一個(gè) IPv4 的加一個(gè) IPv6 的)。
The port parameter can be set to specify which port the server should listen on. If
0orNone(the default), a random unused port will be selected (note that if host resolves to multiple network interfaces, a different random port will be selected for each interface).family 可被設(shè)為
socket.AF_INET或AF_INET6以強(qiáng)制此套接字使用 IPv4 或 IPv6。 如果未設(shè)定,則 family 將通過(guò)主機(jī)名稱(chēng)來(lái)確定 (默認(rèn)為AF_UNSPEC)。flags 是用于
getaddrinfo()的位掩碼。可以選擇指定 sock 以便使用預(yù)先存在的套接字對(duì)象。 如果指定了此參數(shù),則不可再指定 host 和 port。
backlog 是傳遞給
listen()的最大排隊(duì)連接的數(shù)量(默認(rèn)為100)。ssl 可被設(shè)置為一個(gè)
SSLContext實(shí)例以在所接受的連接上啟用 TLS。reuse_address 告知內(nèi)核要重用一個(gè)處于
TIME_WAIT狀態(tài)的本地套接字,而不是等待其自然超時(shí)失效。 如果未指定此參數(shù)則在 Unix 上將自動(dòng)設(shè)置為True。reuse_port 告知內(nèi)核,只要在創(chuàng)建的時(shí)候都設(shè)置了這個(gè)標(biāo)志,就允許此端點(diǎn)綁定到其它端點(diǎn)列表所綁定的同樣的端口上。這個(gè)選項(xiàng)在 Windows 上是不支持的。
ssl_handshake_timeout 是(用于 TLS 服務(wù)器的)在放棄連接之前要等待 TLS 握手完成的秒數(shù)。 如果參數(shù)為 (默認(rèn)值)
None則為60.0秒。ssl_shutdown_timeout is the time in seconds to wait for the SSL shutdown to complete before aborting the connection.
30.0seconds ifNone(default).start_serving 設(shè)置成
True(默認(rèn)值) 會(huì)導(dǎo)致創(chuàng)建server并立即開(kāi)始接受連接。設(shè)置成False,用戶(hù)需要等待Server.start_serving()或者Server.serve_forever()以使server開(kāi)始接受連接。
在 3.5 版更改:
ProactorEventLoop類(lèi)中添加 SSL/TLS 支持。在 3.5.1 版更改: host 形參可以是一個(gè)字符串的序列。
在 3.6 版更改: Added ssl_handshake_timeout and start_serving parameters. The socket option
TCP_NODELAYis set by default for all TCP connections.在 3.11 版更改: Added the ssl_shutdown_timeout parameter.
參見(jiàn)
start_server()函數(shù)是一個(gè)高層級(jí)的替代 API,它返回一對(duì)StreamReader和StreamWriter,可在 async/await 代碼中使用。
- coroutine loop.create_unix_server(protocol_factory, path=None, *, sock=None, backlog=100, ssl=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, start_serving=True)?
與
loop.create_server()類(lèi)似但是專(zhuān)用于AF_UNIX套接字族。path 是必要的 Unix 域套接字名稱(chēng),除非提供了 sock 參數(shù)。 抽象的 Unix 套接字,
str,bytes和Path路徑都是受支持的。請(qǐng)查看
loop.create_server()方法的文檔了解有關(guān)此方法的參數(shù)的信息。可用性: Unix。
在 3.7 版更改: Added the ssl_handshake_timeout and start_serving parameters. The path parameter can now be a
Pathobject.在 3.11 版更改: Added the ssl_shutdown_timeout parameter.
- coroutine loop.connect_accepted_socket(protocol_factory, sock, *, ssl=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None)?
將已被接受的連接包裝成一個(gè)傳輸/協(xié)議對(duì)。
此方法可被服務(wù)器用來(lái)接受 asyncio 以外的連接,但是使用 asyncio 來(lái)處理它們。
參數(shù):
protocol_factory 必須為一個(gè)返回 協(xié)議 實(shí)現(xiàn)的可調(diào)用對(duì)象。
sock 是一個(gè)預(yù)先存在的套接字對(duì)象,它是由
socket.accept返回的。ssl 可被設(shè)置為一個(gè)
SSLContext以在接受的連接上啟用 SSL。ssl_handshake_timeout 是(為一個(gè)SSL連接)在中止連接前,等待SSL握手完成的時(shí)間【單位秒】。如果為
None(缺省) 則是60.0秒。ssl_shutdown_timeout is the time in seconds to wait for the SSL shutdown to complete before aborting the connection.
30.0seconds ifNone(default).
返回一個(gè)
(transport, protocol)對(duì)。3.5.3 新版功能.
在 3.7 版更改: Added the ssl_handshake_timeout parameter.
在 3.11 版更改: Added the ssl_shutdown_timeout parameter.
傳輸文件?
- coroutine loop.sendfile(transport, file, offset=0, count=None, *, fallback=True)?
將 file 通過(guò) transport 發(fā)送。 返回所發(fā)送的字節(jié)總數(shù)。
如果可用的話(huà),該方法將使用高性能的
os.sendfile()。file 必須是個(gè)二進(jìn)制模式打開(kāi)的常規(guī)文件對(duì)象。
offset 指明從何處開(kāi)始讀取文件。 如果指定了 count,它是要傳輸?shù)淖止?jié)總數(shù)而不再一直發(fā)送文件直至抵達(dá) EOF。 文件位置總是會(huì)被更新,即使此方法引發(fā)了錯(cuò)誤,并可以使用
file.tell()來(lái)獲取實(shí)際發(fā)送的字節(jié)總數(shù)。fallback 設(shè)為
True會(huì)使得 asyncio 在平臺(tái)不支持 sendfile 系統(tǒng)調(diào)用時(shí)手動(dòng)讀取并發(fā)送文件(例如 Windows 或 Unix 上的 SSL 套接字)。如果系統(tǒng)不支持 sendfile 系統(tǒng)調(diào)用且 fallback 為
False則會(huì)引發(fā)SendfileNotAvailableError。3.7 新版功能.
TLS 升級(jí)?
- coroutine loop.start_tls(transport, protocol, sslcontext, *, server_side=False, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None)?
將現(xiàn)有基于傳輸?shù)倪B接升級(jí)到 TLS。
返回一個(gè)新的傳輸實(shí)例,其中 protocol 必須在 await 之后立即開(kāi)始使用。 傳給 start_tls 方法的 transport 實(shí)例應(yīng)永遠(yuǎn)不會(huì)被再次使用。
參數(shù):
transport 和 protocol 實(shí)例的方法與
create_server()和create_connection()所返回的類(lèi)似。sslcontext :一個(gè)已經(jīng)配置好的
SSLContext實(shí)例。當(dāng)服務(wù)端連接已升級(jí)時(shí) (如
create_server()所創(chuàng)建的對(duì)象) server_side 會(huì)傳入True。server_hostname :設(shè)置或者覆蓋目標(biāo)服務(wù)器證書(shū)中相對(duì)應(yīng)的主機(jī)名。
ssl_handshake_timeout 是(用于 TLS 連接的)在放棄連接之前要等待 TLS 握手完成的秒數(shù)。 如果參數(shù)為
None則使用 (默認(rèn)的)60.0。ssl_shutdown_timeout is the time in seconds to wait for the SSL shutdown to complete before aborting the connection.
30.0seconds ifNone(default).
3.7 新版功能.
在 3.11 版更改: Added the ssl_shutdown_timeout parameter.
監(jiān)控文件描述符?
- loop.add_reader(fd, callback, *args)?
開(kāi)始監(jiān)視 fd 文件描述符以獲取讀取的可用性,一旦 fd 可用于讀取,使用指定的參數(shù)調(diào)用 callback 。
- loop.remove_reader(fd)?
停止對(duì)文件描述符 fd 讀取可用性的監(jiān)視。
- loop.add_writer(fd, callback, *args)?
開(kāi)始監(jiān)視 fd 文件描述符的寫(xiě)入可用性,一旦 fd 可用于寫(xiě)入,使用指定的參數(shù)調(diào)用 callback 。
使用
functools.partial()傳遞關(guān)鍵字參數(shù) 給 callback.
- loop.remove_writer(fd)?
停止對(duì)文件描述符 fd 的寫(xiě)入可用性監(jiān)視。
另請(qǐng)查看 平臺(tái)支持 一節(jié)了解以上方法的某些限制。
直接使用 socket 對(duì)象?
通常,使用基于傳輸?shù)?API 的協(xié)議實(shí)現(xiàn),例如 loop.create_connection() 和 loop.create_server() 比直接使用套接字的實(shí)現(xiàn)更快。 但是,在某些應(yīng)用場(chǎng)景下性能并不非常重要,直接使用 socket 對(duì)象會(huì)更方便。
- coroutine loop.sock_recv(sock, nbytes)?
從 sock 接收至多 nbytes。
socket.recv()的異步版本。返回接收到的數(shù)據(jù)【bytes對(duì)象類(lèi)型】。
sock 必須是個(gè)非阻塞socket。
在 3.7 版更改: 雖然這個(gè)方法總是被記錄為協(xié)程方法,但它在 Python 3.7 之前的發(fā)行版中會(huì)返回一個(gè)
Future。 從 Python 3.7 開(kāi)始它則是一個(gè)async def方法。
- coroutine loop.sock_recv_into(sock, buf)?
從 sock 接收數(shù)據(jù)放入 buf 緩沖區(qū)。 模仿了阻塞型的
socket.recv_into()方法。返回寫(xiě)入緩沖區(qū)的字節(jié)數(shù)。
sock 必須是個(gè)非阻塞socket。
3.7 新版功能.
- coroutine loop.sock_recvfrom(sock, bufsize)?
Receive a datagram of up to bufsize from sock. Asynchronous version of
socket.recvfrom().Return a tuple of (received data, remote address).
sock 必須是個(gè)非阻塞socket。
3.11 新版功能.
- coroutine loop.sock_recvfrom_into(sock, buf, nbytes=0)?
Receive a datagram of up to nbytes from sock into buf. Asynchronous version of
socket.recvfrom_into().Return a tuple of (number of bytes received, remote address).
sock 必須是個(gè)非阻塞socket。
3.11 新版功能.
- coroutine loop.sock_sendall(sock, data)?
將 data 發(fā)送到 sock 套接字。
socket.sendall()的異步版本。此方法會(huì)持續(xù)發(fā)送數(shù)據(jù)到套接字直至 data 中的所有數(shù)據(jù)發(fā)送完畢或是有錯(cuò)誤發(fā)生。 當(dāng)成功時(shí)會(huì)返回
None。 當(dāng)發(fā)生錯(cuò)誤時(shí),會(huì)引發(fā)一個(gè)異常。 此外,沒(méi)有辦法能確定有多少數(shù)據(jù)或是否有數(shù)據(jù)被連接的接收方成功處理。sock 必須是個(gè)非阻塞socket。
在 3.7 版更改: 雖然這個(gè)方法一直被標(biāo)記為協(xié)程方法。但是,Python 3.7 之前,該方法返回
Future,從Python 3.7 開(kāi)始,這個(gè)方法是async def方法。
- coroutine loop.sock_sendto(sock, data, address)?
Send a datagram from sock to address. Asynchronous version of
socket.sendto().Return the number of bytes sent.
sock 必須是個(gè)非阻塞socket。
3.11 新版功能.
- coroutine loop.sock_connect(sock, address)?
將 sock 連接到位于 address 的遠(yuǎn)程套接字。
socket.connect()的異步版本。sock 必須是個(gè)非阻塞socket。
在 3.5.2 版更改:
address不再需要被解析。sock_connect將嘗試檢查 address 是否已通過(guò)調(diào)用socket.inet_pton()被解析。 如果沒(méi)有,則將使用loop.getaddrinfo()來(lái)解析 address。參見(jiàn)
- coroutine loop.sock_accept(sock)?
接受一個(gè)連接。 模仿了阻塞型的
socket.accept()方法。此 scoket 必須綁定到一個(gè)地址上并且監(jiān)聽(tīng)連接。返回值是一個(gè)
(conn, address)對(duì),其中 conn 是一個(gè) 新*的套接字對(duì)象,用于在此連接上收發(fā)數(shù)據(jù),*address 是連接的另一端的套接字所綁定的地址。sock 必須是個(gè)非阻塞socket。
在 3.7 版更改: 雖然這個(gè)方法一直被標(biāo)記為協(xié)程方法。但是,Python 3.7 之前,該方法返回
Future,從Python 3.7 開(kāi)始,這個(gè)方法是async def方法。參見(jiàn)
- coroutine loop.sock_sendfile(sock, file, offset=0, count=None, *, fallback=True)?
在可能的情況下使用高性能的
os.sendfile發(fā)送文件。 返回所發(fā)送的字節(jié)總數(shù)。socket.sendfile()的異步版本。sock 必須為非阻塞型的
socket.SOCK_STREAMsocket。file 必須是個(gè)用二進(jìn)制方式打開(kāi)的常規(guī)文件對(duì)象。
offset 指明從何處開(kāi)始讀取文件。 如果指定了 count,它是要傳輸?shù)淖止?jié)總數(shù)而不再一直發(fā)送文件直至抵達(dá) EOF。 文件位置總是會(huì)被更新,即使此方法引發(fā)了錯(cuò)誤,并可以使用
file.tell()來(lái)獲取實(shí)際發(fā)送的字節(jié)總數(shù)。當(dāng) fallback 被設(shè)為
True時(shí),會(huì)使用 asyncio 在平臺(tái)不支持 sendfile 系統(tǒng)調(diào)用時(shí)手動(dòng)讀取并發(fā)送文件(例如 Windows 或 Unix 上的 SSL 套接字)。如果系統(tǒng)不支持 sendfile 并且 fallback 為
False,引發(fā)SendfileNotAvailableError異常。sock 必須是個(gè)非阻塞socket。
3.7 新版功能.
DNS?
- coroutine loop.getaddrinfo(host, port, *, family=0, type=0, proto=0, flags=0)?
異步版的
socket.getaddrinfo()。
- coroutine loop.getnameinfo(sockaddr, flags=0)?
異步版的
socket.getnameinfo()。
在 3.7 版更改: getaddrinfo 和 getnameinfo 方法一直被標(biāo)記返回一個(gè)協(xié)程,但是Python 3.7之前,實(shí)際返回的是 asyncio.Future 對(duì)象。從Python 3.7 開(kāi)始,這兩個(gè)方法是協(xié)程。
使用管道?
- coroutine loop.connect_read_pipe(protocol_factory, pipe)?
在事件循環(huán)中注冊(cè) pipe 的讀取端。
protocol_factory 必須為一個(gè)返回 asyncio 協(xié)議 實(shí)現(xiàn)的可調(diào)用對(duì)象。
pipe 是個(gè) 類(lèi)似文件型對(duì)象.
返回一對(duì)
(transport, protocol),其中 transport 支持ReadTransport接口而 protocol 是由 protocol_factory 所實(shí)例化的對(duì)象。使用
SelectorEventLoop事件循環(huán), pipe 被設(shè)置為非阻塞模式。
- coroutine loop.connect_write_pipe(protocol_factory, pipe)?
在事件循環(huán)中注冊(cè) pipe 的寫(xiě)入端。
protocol_factory 必須為一個(gè)返回 asyncio 協(xié)議 實(shí)現(xiàn)的可調(diào)用對(duì)象。
pipe 是個(gè) 類(lèi)似文件型對(duì)象.
返回一對(duì)
(transport, protocol),其中 transport 支持WriteTransport接口而 protocol 是由 protocol_factory 所實(shí)例化的對(duì)象。使用
SelectorEventLoop事件循環(huán), pipe 被設(shè)置為非阻塞模式。
備注
在 Windows 中 SelectorEventLoop 不支持上述方法。 對(duì)于 Windows 請(qǐng)改用 ProactorEventLoop。
參見(jiàn)
Unix 信號(hào)?
- loop.add_signal_handler(signum, callback, *args)?
設(shè)置 callback 作為 signum 信號(hào)的處理程序。
此回調(diào)將與該事件循環(huán)中其他加入隊(duì)列的回調(diào)和可運(yùn)行協(xié)程一起由 loop 發(fā)起調(diào)用。 不同與使用
signal.signal()注冊(cè)的信號(hào)處理程序,使用此函數(shù)注冊(cè)的回調(diào)可以與事件循環(huán)進(jìn)行交互。如果信號(hào)數(shù)字非法或者不可捕獲,就拋出一個(gè)
ValueError。如果建立處理器的過(guò)程中出現(xiàn)問(wèn)題,會(huì)拋出一個(gè)RuntimeError。使用
functools.partial()傳遞關(guān)鍵字參數(shù) 給 callback.和
signal.signal()一樣,這個(gè)函數(shù)只能在主線(xiàn)程中調(diào)用。
- loop.remove_signal_handler(sig)?
移除 sig 信號(hào)的處理程序。
如果信號(hào)處理程序被移除則返回
True,否則如果給定信號(hào)未設(shè)置處理程序則返回False。可用性: Unix。
參見(jiàn)
signal 模塊。
在線(xiàn)程或者進(jìn)程池中執(zhí)行代碼。?
- awaitable loop.run_in_executor(executor, func, *args)?
安排在指定的執(zhí)行器中調(diào)用 func 。
The executor argument should be an
concurrent.futures.Executorinstance. The default executor is used if executor isNone.示例:
import asyncio import concurrent.futures def blocking_io(): # File operations (such as logging) can block the # event loop: run them in a thread pool. with open('/dev/urandom', 'rb') as f: return f.read(100) def cpu_bound(): # CPU-bound operations will block the event loop: # in general it is preferable to run them in a # process pool. return sum(i * i for i in range(10 ** 7)) async def main(): loop = asyncio.get_running_loop() ## Options: # 1. Run in the default loop's executor: result = await loop.run_in_executor( None, blocking_io) print('default thread pool', result) # 2. Run in a custom thread pool: with concurrent.futures.ThreadPoolExecutor() as pool: result = await loop.run_in_executor( pool, blocking_io) print('custom thread pool', result) # 3. Run in a custom process pool: with concurrent.futures.ProcessPoolExecutor() as pool: result = await loop.run_in_executor( pool, cpu_bound) print('custom process pool', result) asyncio.run(main())
這個(gè)方法返回一個(gè)
asyncio.Future對(duì)象。使用
functools.partial()傳遞關(guān)鍵字參數(shù) 給 func 。在 3.5.3 版更改:
loop.run_in_executor()不會(huì)再配置它所創(chuàng)建的線(xiàn)程池執(zhí)行器的max_workers,而是將其留給線(xiàn)程池執(zhí)行器 (ThreadPoolExecutor) 來(lái)設(shè)置默認(rèn)值。
- loop.set_default_executor(executor)?
Set executor as the default executor used by
run_in_executor(). executor must be an instance ofThreadPoolExecutor.在 3.11 版更改: executor must be an instance of
ThreadPoolExecutor.
錯(cuò)誤處理API?
允許自定義事件循環(huán)中如何去處理異常。
- loop.set_exception_handler(handler)?
將 handler 設(shè)置為新的事件循環(huán)異常處理器。
如果 handler 為
None,將設(shè)置默認(rèn)的異常處理程序。 在其他情況下,handler 必須是一個(gè)可調(diào)用對(duì)象且簽名匹配(loop, context),其中loop是對(duì)活動(dòng)事件循環(huán)的引用,而context是一個(gè)包含異常詳情的dict(請(qǐng)查看call_exception_handler()文檔來(lái)獲取關(guān)于上下文的更多信息)。
- loop.get_exception_handler()?
返回當(dāng)前的異常處理器,如果沒(méi)有設(shè)置異常處理器,則返回
None。3.5.2 新版功能.
- loop.default_exception_handler(context)?
默認(rèn)的異常處理器。
此方法會(huì)在發(fā)生異常且未設(shè)置異常處理程序時(shí)被調(diào)用。 此方法也可以由想要具有不同于默認(rèn)處理程序的行為的自定義異常處理程序來(lái)調(diào)用。
context 參數(shù)和
call_exception_handler()中的同名參數(shù)完全相同。
- loop.call_exception_handler(context)?
調(diào)用當(dāng)前事件循環(huán)的異常處理器。
context 是個(gè)包含下列鍵的
dict對(duì)象(未來(lái)版本的Python可能會(huì)引入新鍵):'message': 錯(cuò)誤消息;
'exception' (可選): 異常對(duì)象;
'future' (可選):
asyncio.Future實(shí)例;'task' (可選):
asyncio.Task實(shí)例;'handle' (可選):
asyncio.Handle實(shí)例;'protocol' (可選): Protocol 實(shí)例;
'transport' (可選): Transport 實(shí)例;
'socket' (可選):
socket.socket實(shí)例;- 'asyncgen' (可選): 異步生成器,它導(dǎo)致了
這個(gè)異常
備注
此方法不應(yīng)在子類(lèi)化的事件循環(huán)中被重載。 對(duì)于自定義的異常處理,請(qǐng)使用
set_exception_handler()方法。
開(kāi)啟調(diào)試模式?
- loop.get_debug()?
獲取事件循環(huán)調(diào)試模式設(shè)置(
bool)。如果環(huán)境變量
PYTHONASYNCIODEBUG是一個(gè)非空字符串,就返回True,否則就返回False。
- loop.set_debug(enabled: bool)?
設(shè)置事件循環(huán)的調(diào)試模式。
在 3.7 版更改: 現(xiàn)在也可以通過(guò)新的 Python 開(kāi)發(fā)模式 來(lái)啟用調(diào)試模式。
參見(jiàn)
運(yùn)行子進(jìn)程?
本小節(jié)所描述的方法都是低層級(jí)的。 在常規(guī) async/await 代碼中請(qǐng)考慮改用高層級(jí)的 asyncio.create_subprocess_shell() 和 asyncio.create_subprocess_exec() 便捷函數(shù)。
備注
On Windows, the default event loop ProactorEventLoop supports
subprocesses, whereas SelectorEventLoop does not. See
Subprocess Support on Windows for
details.
- coroutine loop.subprocess_exec(protocol_factory, *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)?
用 args 指定的一個(gè)或者多個(gè)字符串型參數(shù)創(chuàng)建一個(gè)子進(jìn)程。
args 必須是個(gè)由下列形式的字符串組成的列表:
str;或者由 文件系統(tǒng)編碼格式 編碼的
bytes。
第一個(gè)字符串指定可執(zhí)行程序,其余的字符串指定其參數(shù)。 所有字符串參數(shù)共同組成了程序的
argv。此方法類(lèi)似于調(diào)用標(biāo)準(zhǔn)庫(kù)
subprocess.Popen類(lèi),設(shè)置shell=False并將字符串列表作為第一個(gè)參數(shù)傳入;但是,Popen只接受一個(gè)單獨(dú)的字符串列表參數(shù),而 subprocess_exec 接受多個(gè)字符串參數(shù)。protocol_factory 必須為一個(gè)返回
asyncio.SubprocessProtocol類(lèi)的子類(lèi)的可調(diào)用對(duì)象。其他參數(shù):
stdin 可以是以下對(duì)象之一:
一個(gè)文件類(lèi)對(duì)象,表示要使用
connect_write_pipe()連接到子進(jìn)程的標(biāo)準(zhǔn)輸入流的管道subprocess.PIPE常量(默認(rèn)),將創(chuàng)建并連接一個(gè)新的管道。None值,這將使得子進(jìn)程繼承來(lái)自此進(jìn)程的文件描述符subprocess.DEVNULL常量,這表示將使用特殊的os.devnull文件
stdout 可以是以下對(duì)象之一:
一個(gè)文件類(lèi)對(duì)象,表示要使用
connect_write_pipe()連接到子進(jìn)程的標(biāo)準(zhǔn)輸出流的管道subprocess.PIPE常量(默認(rèn)),將創(chuàng)建并連接一個(gè)新的管道。None值,這將使得子進(jìn)程繼承來(lái)自此進(jìn)程的文件描述符subprocess.DEVNULL常量,這表示將使用特殊的os.devnull文件
stderr 可以是以下對(duì)象之一:
一個(gè)文件類(lèi)對(duì)象,表示要使用
connect_write_pipe()連接到子進(jìn)程的標(biāo)準(zhǔn)錯(cuò)誤流的管道subprocess.PIPE常量(默認(rèn)),將創(chuàng)建并連接一個(gè)新的管道。None值,這將使得子進(jìn)程繼承來(lái)自此進(jìn)程的文件描述符subprocess.DEVNULL常量,這表示將使用特殊的os.devnull文件subprocess.STDOUT常量,將把標(biāo)準(zhǔn)錯(cuò)誤流連接到進(jìn)程的標(biāo)準(zhǔn)輸出流
所有其他關(guān)鍵字參數(shù)會(huì)被不加解釋地傳給
subprocess.Popen,除了 bufsize, universal_newlines, shell, text, encoding 和 errors,它們都不應(yīng)當(dāng)被指定。asyncio子進(jìn)程 API 不支持將流解碼為文本。 可以使用bytes.decode()來(lái)將從流返回的字節(jié)串轉(zhuǎn)換為文本。
其他參數(shù)的文檔,請(qǐng)參閱
subprocess.Popen類(lèi)的構(gòu)造函數(shù)。返回一對(duì)
(transport, protocol),其中 transport 來(lái)自asyncio.SubprocessTransport基類(lèi)而 protocol 是由 protocol_factory 所實(shí)例化的對(duì)象。
- coroutine loop.subprocess_shell(protocol_factory, cmd, *, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)?
基于 cmd 創(chuàng)建一個(gè)子進(jìn)程,該參數(shù)可以是一個(gè)
str或者按 文件系統(tǒng)編碼格式 編碼得到的bytes,使用平臺(tái)的 "shell" 語(yǔ)法。這類(lèi)似與用
shell=True調(diào)用標(biāo)準(zhǔn)庫(kù)的subprocess.Popen類(lèi)。protocol_factory 必須為一個(gè)返回
SubprocessProtocol類(lèi)的子類(lèi)的可調(diào)用對(duì)象。請(qǐng)參閱
subprocess_exec()了解有關(guān)其余參數(shù)的詳情。返回一對(duì)
(transport, protocol),其中 transport 來(lái)自SubprocessTransport基類(lèi)而 protocol 是由 protocol_factory 所實(shí)例化的對(duì)象。
備注
應(yīng)用程序要負(fù)責(zé)確保正確地轉(zhuǎn)義所有空白字符和特殊字符以防止 shell 注入 漏洞。 shlex.quote() 函數(shù)可以被用來(lái)正確地轉(zhuǎn)義字符串中可能被用來(lái)構(gòu)造 shell 命令的空白字符和特殊字符。
回調(diào)處理?
- class asyncio.Handle?
由
loop.call_soon(),loop.call_soon_threadsafe()所返回的回調(diào)包裝器對(duì)象。- cancel()?
取消回調(diào)。 如果此回調(diào)已被取消或已被執(zhí)行,此方法將沒(méi)有任何效果。
- cancelled()?
如果此回調(diào)已被取消則返回
True。3.7 新版功能.
- class asyncio.TimerHandle?
由
loop.call_later()和loop.call_at()所返回的回調(diào)包裝器對(duì)象。這個(gè)類(lèi)是
Handle的子類(lèi)。- when()?
返回加入計(jì)劃任務(wù)的回調(diào)時(shí)間,以
float值表示的秒數(shù)。時(shí)間值是一個(gè)絕對(duì)時(shí)間戳,使用與
loop.time()相同的時(shí)間引用。3.7 新版功能.
Server 對(duì)象?
Server 對(duì)象可使用 loop.create_server(), loop.create_unix_server(), start_server() 和 start_unix_server() 等函數(shù)來(lái)創(chuàng)建。
請(qǐng)不要直接實(shí)例化該類(lèi)。
- class asyncio.Server?
Server 對(duì)象是異步上下文管理器。當(dāng)用于
async with語(yǔ)句時(shí),異步上下文管理器可以確保 Server 對(duì)象被關(guān)閉,并且在async with語(yǔ)句完成后,不接受新的連接。srv = await loop.create_server(...) async with srv: # some code # At this point, srv is closed and no longer accepts new connections.
在 3.7 版更改: Python3.7 開(kāi)始,Server 對(duì)象是一個(gè)異步上下文管理器。
- close()?
停止服務(wù):關(guān)閉監(jiān)聽(tīng)的套接字并且設(shè)置
sockets屬性為None。用于表示已經(jīng)連進(jìn)來(lái)的客戶(hù)端連接會(huì)保持打開(kāi)的狀態(tài)。
服務(wù)器是被異步關(guān)閉的,使用
wait_closed()協(xié)程來(lái)等待服務(wù)器關(guān)閉。
- get_loop()?
返回與服務(wù)器對(duì)象相關(guān)聯(lián)的事件循環(huán)。
3.7 新版功能.
- coroutine start_serving()?
開(kāi)始接受連接。
This method is idempotent, so it can be called when the server is already serving.
傳給
loop.create_server()和asyncio.start_server()的 start_serving 僅限關(guān)鍵字形參允許創(chuàng)建不接受初始連接的 Server 對(duì)象。 在此情況下可以使用Server.start_serving()或Server.serve_forever()讓 Server 對(duì)象開(kāi)始接受連接。3.7 新版功能.
- coroutine serve_forever()?
開(kāi)始接受連接,直到協(xié)程被取消。
serve_forever任務(wù)的取消將導(dǎo)致服務(wù)器被關(guān)閉。如果服務(wù)器已經(jīng)在接受連接了,這個(gè)方法可以被調(diào)用。每個(gè) Server 對(duì)象,僅能有一個(gè)
serve_forever任務(wù)。示例:
async def client_connected(reader, writer): # Communicate with the client with # reader/writer streams. For example: await reader.readline() async def main(host, port): srv = await asyncio.start_server( client_connected, host, port) await srv.serve_forever() asyncio.run(main('127.0.0.1', 0))
3.7 新版功能.
- is_serving()?
如果服務(wù)器正在接受新連接的狀態(tài),返回
True。3.7 新版功能.
- sockets?
服務(wù)器監(jiān)聽(tīng)的
socket.socket對(duì)象列表。在 3.7 版更改: 在 Python 3.7 之前
Server.sockets會(huì)直接返回內(nèi)部的服務(wù)器套接字列表。 在 3.7 版則會(huì)返回該列表的副本。
事件循環(huán)實(shí)現(xiàn)?
asyncio 帶有兩種不同的事件循環(huán)實(shí)現(xiàn): SelectorEventLoop 和 ProactorEventLoop。
默認(rèn)情況下 asyncio 被配置為在 Unix 上使用 SelectorEventLoop 而在 Windows 上使用 ProactorEventLoop。
- class asyncio.SelectorEventLoop?
基于
selectors模塊的事件循環(huán)。使用給定平臺(tái)中最高效的可用 selector。 也可以手動(dòng)配置要使用的特定 selector:
import asyncio import selectors selector = selectors.SelectSelector() loop = asyncio.SelectorEventLoop(selector) asyncio.set_event_loop(loop)
可用性: Unix, Windows。
- class asyncio.ProactorEventLoop?
用 "I/O Completion Ports" (IOCP) 構(gòu)建的專(zhuān)為Windows 的事件循環(huán)。
可用性: Windows。
參見(jiàn)
- class asyncio.AbstractEventLoop?
asyncio 兼容事件循環(huán)的抽象基類(lèi)。
事件循環(huán)方法 一節(jié)列出了
AbstractEventLoop的替代實(shí)現(xiàn)應(yīng)當(dāng)定義的所有方法。
例子?
請(qǐng)注意本節(jié)中的所有示例都 有意地 演示了如何使用低層級(jí)的事件循環(huán) API,例如 loop.run_forever() 和 loop.call_soon()。 現(xiàn)代的 asyncio 應(yīng)用很少需要以這樣的方式編寫(xiě);請(qǐng)考慮使用高層級(jí)的函數(shù)例如 asyncio.run()。
call_soon() 的 Hello World 示例。?
一個(gè)使用 loop.call_soon() 方法來(lái)安排回調(diào)的示例。 回調(diào)會(huì)顯示 "Hello World" 然后停止事件循環(huán):
import asyncio
def hello_world(loop):
"""A callback to print 'Hello World' and stop the event 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()
try:
loop.run_forever()
finally:
loop.close()
參見(jiàn)
一個(gè)類(lèi)似的 Hello World 示例,使用協(xié)程和 run() 函數(shù)創(chuàng)建。
使用 call_later() 來(lái)展示當(dāng)前的日期?
一個(gè)每秒刷新顯示當(dāng)前日期的示例。 回調(diào)使用 loop.call_later() 方法在 5 秒后將自身重新加入計(jì)劃日程,然后停止事件循環(huán):
import asyncio
import datetime
def display_date(end_time, loop):
print(datetime.datetime.now())
if (loop.time() + 1.0) < end_time:
loop.call_later(1, display_date, end_time, loop)
else:
loop.stop()
loop = asyncio.get_event_loop()
# Schedule the first call to display_date()
end_time = loop.time() + 5.0
loop.call_soon(display_date, end_time, loop)
# Blocking call interrupted by loop.stop()
try:
loop.run_forever()
finally:
loop.close()
參見(jiàn)
一個(gè)類(lèi)似的 current date 示例,使用協(xié)程和 run() 函數(shù)創(chuàng)建。
監(jiān)控一個(gè)文件描述符的讀事件?
使用 loop.add_reader() 方法,等到文件描述符收到一些數(shù)據(jù),然后關(guān)閉事件循環(huán):
import asyncio
from socket import socketpair
# Create a pair of connected file descriptors
rsock, wsock = socketpair()
loop = asyncio.get_event_loop()
def reader():
data = rsock.recv(100)
print("Received:", data.decode())
# We are done: unregister the file descriptor
loop.remove_reader(rsock)
# Stop the event loop
loop.stop()
# Register the file descriptor for read event
loop.add_reader(rsock, reader)
# Simulate the reception of data from the network
loop.call_soon(wsock.send, 'abc'.encode())
try:
# Run the event loop
loop.run_forever()
finally:
# We are done. Close sockets and the event loop.
rsock.close()
wsock.close()
loop.close()
參見(jiàn)
一個(gè)類(lèi)似的 示例,使用傳輸、協(xié)議和
loop.create_connection()方法創(chuàng)建。另一個(gè)類(lèi)似的 示例,使用了高層級(jí)的
asyncio.open_connection()函數(shù)和流。
為SIGINT和SIGTERM設(shè)置信號(hào)處理器?
(這個(gè) signals 示例只適用于 Unix。)
使用 loop.add_signal_handler() 方法為信號(hào) SIGINT 和 SIGTERM 注冊(cè)處理程序:
import asyncio
import functools
import os
import signal
def ask_exit(signame, loop):
print("got signal %s: exit" % signame)
loop.stop()
async def main():
loop = asyncio.get_running_loop()
for signame in {'SIGINT', 'SIGTERM'}:
loop.add_signal_handler(
getattr(signal, signame),
functools.partial(ask_exit, signame, loop))
await asyncio.sleep(3600)
print("Event loop running for 1 hour, press Ctrl+C to interrupt.")
print(f"pid {os.getpid()}: send SIGINT or SIGTERM to exit.")
asyncio.run(main())