tornado.ioloop
— 主要事件迴圈¶
一個用於非阻塞式 socket 的 I/O 事件迴圈。
在 Tornado 6.0 中,IOLoop
是 asyncio
事件迴圈的包裝器,具有稍微不同的介面。IOLoop
介面現在主要為了向後相容性而提供;新的程式碼通常應直接使用 asyncio
事件迴圈介面。IOLoop.current
類別方法提供對應於正在執行的 asyncio
事件迴圈的 IOLoop
實例。
IOLoop 物件¶
- class tornado.ioloop.IOLoop(*args: Any, **kwargs: Any)[原始碼]¶
一個 I/O 事件迴圈。
從 Tornado 6.0 開始,
IOLoop
是asyncio
事件迴圈的包裝器。簡單 TCP 伺服器的使用範例
import asyncio import errno import functools import socket import tornado from tornado.iostream import IOStream async def handle_connection(connection, address): stream = IOStream(connection) message = await stream.read_until_close() print("message from client:", message.decode().strip()) def connection_ready(sock, fd, events): while True: try: connection, address = sock.accept() except BlockingIOError: return connection.setblocking(0) io_loop = tornado.ioloop.IOLoop.current() io_loop.spawn_callback(handle_connection, connection, address) async def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setblocking(0) sock.bind(("", 8888)) sock.listen(128) io_loop = tornado.ioloop.IOLoop.current() callback = functools.partial(connection_ready, sock) io_loop.add_handler(sock.fileno(), callback, io_loop.READ) await asyncio.Event().wait() if __name__ == "__main__": asyncio.run(main())
大多數應用程式不應嘗試直接建構
IOLoop
,而應初始化asyncio
事件迴圈並使用IOLoop.current()
。在某些情況下,例如在測試框架中初始化要在輔助執行緒中執行的IOLoop
時,可以使用IOLoop(make_current=False)
建構IOLoop
。一般而言,
IOLoop
無法在 fork 後存活,也無法以任何方式跨進程共享。當使用多個進程時,每個進程都應建立自己的IOLoop
,這也表示任何依賴IOLoop
的物件(例如AsyncHTTPClient
)也必須在子進程中建立。作為指導原則,任何啟動進程的程式碼(包括tornado.process
和multiprocessing
模組)應盡早執行,理想情況下,應在應用程式載入組態後立即執行,並且在任何呼叫IOLoop.start
或asyncio.run
之前執行。在 4.2 版更改: 為
IOLoop
建構子新增了make_current
關鍵字引數。在 6.3 版更改: 現在建立 IOLoop 時,預設值為
make_current=True
- 之前預設值為如果沒有目前的事件迴圈,則將其設為目前的事件迴圈。
執行 IOLoop¶
- static IOLoop.current() IOLoop [原始碼]¶
- static IOLoop.current(instance: bool = True) Optional[IOLoop]
傳回目前執行緒的
IOLoop
。如果
IOLoop
目前正在執行,或已由make_current
標記為目前的,則傳回該實例。如果沒有目前的IOLoop
且instance
為 true,則建立一個。在 4.1 版更改: 新增了
instance
引數,以控制回退至IOLoop.instance()
。變更於版本 5.0:在 Python 3 上,目前
IOLoop
的控制權委派給asyncio
,此方法和其他方法作為傳遞存取器。instance
參數現在控制是否在沒有IOLoop
時自動建立一個,而不是是否回退到IOLoop.instance()
(現在是此方法的別名)。instance=False
已棄用,因為即使我們不建立IOLoop
,此方法也可能會初始化 asyncio 迴圈。自版本 6.2 起已棄用:當沒有
asyncio
事件迴圈正在執行時呼叫IOLoop.current()
已被棄用。
- IOLoop.make_current() None [原始碼]¶
使這個成為目前執行緒的
IOLoop
。當
IOLoop
啟動時,它會自動成為其執行緒的 current,但有時在啟動IOLoop
之前顯式呼叫make_current
是很有用的,以便在啟動時執行的程式碼可以找到正確的實例。變更於版本 5.0:此方法也會設定目前的
asyncio
事件迴圈。自版本 6.2 起已棄用:透過 Tornado 設定和清除 current 事件迴圈已棄用。 如果您需要此功能,請改用
asyncio.set_event_loop
。
- static IOLoop.clear_current() None [原始碼]¶
清除目前執行緒的
IOLoop
。主要用於測試框架在測試之間使用。
變更於版本 5.0:此方法也會清除目前的
asyncio
事件迴圈。自版本 6.2 起已棄用。
- IOLoop.stop() None [原始碼]¶
停止 I/O 迴圈。
如果事件迴圈目前未執行,則下一次呼叫
start()
將立即返回。請注意,即使呼叫
stop
之後,直到IOLoop.start
也返回之前,IOLoop
才會完全停止。 在呼叫stop
之前排定的某些工作,可能仍然會在IOLoop
關閉之前執行。
- IOLoop.run_sync(func: Callable, timeout: Optional[float] = None) Any [原始碼]¶
啟動
IOLoop
、執行給定的函式,並停止迴圈。函式必須返回一個可等待的物件或
None
。 如果函式返回可等待的物件,則IOLoop
將執行直到可等待的物件被解析 (並且run_sync()
將返回可等待物件的結果)。 如果它引發例外,則IOLoop
將停止,並且該例外將會重新引發給呼叫者。僅限關鍵字參數
timeout
可用於設定函式的最長持續時間。 如果逾時到期,則會引發asyncio.TimeoutError
。此方法可用於允許在
main()
函式中進行非同步呼叫async def main(): # do stuff... if __name__ == '__main__': IOLoop.current().run_sync(main)
變更於版本 4.3:返回非
None
的非可等待值現在是一個錯誤。變更於版本 5.0:如果發生逾時,則會取消
func
協程。變更於版本 6.2:
tornado.util.TimeoutError
現在是asyncio.TimeoutError
的別名。
- IOLoop.close(all_fds: bool = False) None [原始碼]¶
關閉
IOLoop
,釋放任何已使用的資源。如果
all_fds
為 true,則將關閉在 IOLoop 上註冊的所有檔案描述符 (不僅是IOLoop
本身建立的檔案描述符)。許多應用程式只會使用單一
IOLoop
,其在整個程序生命週期中執行。在這種情況下,關閉IOLoop
並非必要,因為當程序結束時,一切都會被清理乾淨。IOLoop.close
主要為諸如單元測試等情境提供,這些情境會建立並銷毀大量的IOLoop
。一個
IOLoop
必須在關閉之前完全停止。這表示必須呼叫IOLoop.stop()
且 必須允許IOLoop.start()
返回,然後才能嘗試呼叫IOLoop.close()
。因此,對close
的呼叫通常會出現在對start
的呼叫之後,而不是接近對stop
的呼叫。在 3.1 版更改: 如果
IOLoop
實作支援將非整數物件作為「檔案描述符」,則當all_fds
為 true 時,這些物件將具有其close
方法。
- static IOLoop.instance() IOLoop [原始碼]¶
已棄用的
IOLoop.current()
別名。在 5.0 版更改: 先前,此方法會返回一個全域單例
IOLoop
,與current()
返回的每個執行緒IOLoop
相反。在幾乎所有情況下,兩者都是相同的 (當它們不同時,通常從非 Tornado 執行緒使用,以與主執行緒的IOLoop
通訊)。此區別不存在於asyncio
中,因此為了方便與該套件整合,instance()
已變更為current()
的別名。使用instance()
跨執行緒通訊方面的應用程式應改為設定自己的全域變數,以指向它們想要使用的IOLoop
。自 5.0 版起已棄用。
- IOLoop.install() None [原始碼]¶
已棄用的
make_current()
別名。在 5.0 版更改: 先前,此方法會將此
IOLoop
設定為IOLoop.instance()
使用的全域單例。現在,instance()
是current()
的別名,install()
是make_current()
的別名。自 5.0 版起已棄用。
- static IOLoop.clear_instance() None [原始碼]¶
已棄用的
clear_current()
別名。在 5.0 版更改: 先前,此方法會清除
IOLoop
,其被IOLoop.instance()
用作全域單例。現在,instance()
是current()
的別名,clear_instance()
是clear_current()
的別名。自 5.0 版起已棄用。
I/O 事件¶
- IOLoop.add_handler(fd: int, handler: Callable[[int, int], None], events: int) None [原始碼]¶
- IOLoop.add_handler(fd: _S, handler: Callable[[_S, int], None], events: int) None
註冊給定的處理器以接收
fd
的給定事件。fd
參數可以是整數檔案描述符,也可以是具有fileno()
和close()
方法的類檔案物件。events
參數是常數IOLoop.READ
、IOLoop.WRITE
和IOLoop.ERROR
的位元 OR 運算。當事件發生時,將執行
handler(fd, events)
。在 4.0 版本變更: 新增了傳遞類檔案物件以及原始檔案描述符的功能。
回呼和逾時¶
- IOLoop.add_callback(callback: Callable, *args: Any, **kwargs: Any) None [原始碼]¶
在下一個 I/O 迴圈迭代中呼叫給定的回呼。
在任何時間從任何執行緒呼叫此方法都是安全的,但從訊號處理常式呼叫除外。請注意,這是
IOLoop
中**唯一**提供此執行緒安全保證的方法;所有與IOLoop
的其他互動都必須從該IOLoop
的執行緒完成。add_callback()
可用於將控制權從其他執行緒轉移到IOLoop
的執行緒。
- IOLoop.add_callback_from_signal(callback: Callable, *args: Any, **kwargs: Any) None [原始碼]¶
在下一個 I/O 迴圈迭代中呼叫給定的回呼。
旨在從 Python 訊號處理常式中使用是安全的;不應在其他情況下使用。
自 6.4 版本開始棄用: 請改用
asyncio.AbstractEventLoop.add_signal_handler
。此方法自 Tornado 5.0 以來即被懷疑損壞,並將在 7.0 版本中移除。
- IOLoop.add_future(future: Union[Future[_T], concurrent.futures.Future[_T]], callback: Callable[[Future[_T]], None]) None [原始碼]¶
當給定的
Future
完成時,在IOLoop
上排定一個回呼。回呼會使用一個引數來調用,即
Future
。此方法僅接受
Future
物件,而不接受其他可等待物件(與 Tornado 中大多數情況下兩者可互換使用不同)。
- IOLoop.add_timeout(deadline: Union[float, timedelta], callback: Callable, *args: Any, **kwargs: Any) object [原始碼]¶
在 I/O 迴圈中,於
deadline
指定的時間執行callback
。返回一個不透明的句柄,該句柄可以傳遞給
remove_timeout
以取消。deadline
可以是一個表示時間的數字(與IOLoop.time
使用相同的尺度,通常是time.time
),或是一個datetime.timedelta
物件,表示相對於目前時間的截止時間。自 Tornado 4.0 起,call_later
對於相對時間的情況來說是一個更方便的替代方案,因为它不需要 timedelta 物件。請注意,從其他執行緒呼叫
add_timeout
並不安全。相反地,您必須使用add_callback
將控制權轉移到IOLoop
的執行緒,然後從該處呼叫add_timeout
。IOLoop 的子類別必須實作
add_timeout
或call_at
其中之一;兩者的預設實作將會呼叫另一個。call_at
通常更容易實作,但希望保持與 4.0 之前 Tornado 版本兼容的子類別必須改用add_timeout
。在 4.0 版本中變更:現在會將
*args
和**kwargs
傳遞給回呼函數。
- IOLoop.call_at(when: float, callback: Callable, *args: Any, **kwargs: Any) object [原始碼]¶
在
when
指定的絕對時間執行callback
。when
必須是一個使用與IOLoop.time
相同參考點的數字。返回一個不透明的句柄,該句柄可以傳遞給
remove_timeout
以取消。請注意,與asyncio
中同名的方法不同,返回的物件沒有cancel()
方法。有關執行緒安全和子類別化的註解,請參閱
add_timeout
。4.0 版本中新增。
- IOLoop.call_later(delay: float, callback: Callable, *args: Any, **kwargs: Any) object [原始碼]¶
在
delay
秒過後執行callback
。返回一個不透明的句柄,該句柄可以傳遞給
remove_timeout
以取消。請注意,與asyncio
中同名的方法不同,返回的物件沒有cancel()
方法。有關執行緒安全和子類別化的註解,請參閱
add_timeout
。4.0 版本中新增。
- IOLoop.remove_timeout(timeout: object) None [原始碼]¶
取消待定的逾時。
此參數是由
add_timeout
返回的句柄。即使回呼函數已經執行,呼叫remove_timeout
也是安全的。
- IOLoop.spawn_callback(callback: Callable, *args: Any, **kwargs: Any) None [原始碼]¶
在下一個 IOLoop 迭代中呼叫給定的回呼函數。
自 Tornado 6.0 起,此方法等同於
add_callback
。4.0 版本中新增。
- IOLoop.run_in_executor(executor: Optional[Executor], func: Callable[[...], _T], *args: Any) Future[_T] [原始碼]¶
在
concurrent.futures.Executor
中執行函式。如果executor
為None
,則會使用 IO 迴圈的預設執行器。使用
functools.partial
將關鍵字引數傳遞給func
。5.0 版本新增。
- IOLoop.set_default_executor(executor: Executor) None [原始碼]¶
設定與
run_in_executor()
一起使用的預設執行器。5.0 版本新增。
- IOLoop.time() float [原始碼]¶
根據
IOLoop
的時鐘傳回目前時間。傳回值是相對於過去未指定時間的浮點數。
在歷史上,可以自訂 IOLoop 以使用例如
time.monotonic
而不是time.time
,但目前不支援此功能,因此此方法等同於time.time
。
- class tornado.ioloop.PeriodicCallback(callback: Callable[[], Optional[Awaitable]], callback_time: Union[timedelta, float], jitter: float = 0)[原始碼]¶
排程定期呼叫給定的回呼函式。
當
callback_time
為浮點數時,回呼函式每隔callback_time
毫秒呼叫一次。請注意,逾時時間以毫秒為單位,而 Tornado 中的大多數其他時間相關函式則以秒為單位。callback_time
也可以以datetime.timedelta
物件的形式給定。如果指定
jitter
,則每個回呼時間將在jitter * callback_time
毫秒的視窗內隨機選取。抖動可用於減少具有相似週期的事件的對齊。抖動值為 0.1 表示允許回呼時間有 10% 的變化。視窗以callback_time
為中心,因此在給定間隔內新增抖動不應顯著影響呼叫總數。如果回呼函式的執行時間超過
callback_time
毫秒,則會跳過後續的呼叫以回到排程。在建立
PeriodicCallback
之後,必須呼叫start
。變更於 5.0 版本: 已移除
io_loop
引數(自 4.1 版本起已棄用)。變更於 5.1 版本: 新增
jitter
引數。變更於 6.2 版本: 如果
callback
引數是協程,且回呼函式的執行時間超過callback_time
,則會跳過後續的呼叫。先前,這僅適用於常規函式,不適用於協程,協程對於PeriodicCallback
是「即發即忘」的。除了先前的數值毫秒數之外,
callback_time
引數現在也接受datetime.timedelta
物件。- is_running() bool [原始碼]¶
如果此
PeriodicCallback
已啟動,則傳回True
。4.1 版本新增。