tornado.ioloop — 主要事件迴圈

一個用於非阻塞式 socket 的 I/O 事件迴圈。

在 Tornado 6.0 中,IOLoopasyncio 事件迴圈的包裝器,具有稍微不同的介面。IOLoop 介面現在主要為了向後相容性而提供;新的程式碼通常應直接使用 asyncio 事件迴圈介面。IOLoop.current 類別方法提供對應於正在執行的 asyncio 事件迴圈的 IOLoop 實例。

IOLoop 物件

class tornado.ioloop.IOLoop(*args: Any, **kwargs: Any)[原始碼]

一個 I/O 事件迴圈。

從 Tornado 6.0 開始,IOLoopasyncio 事件迴圈的包裝器。

簡單 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.processmultiprocessing 模組)應盡早執行,理想情況下,應在應用程式載入組態後立即執行,並且在任何呼叫 IOLoop.startasyncio.run 之前執行。

在 4.2 版更改: IOLoop 建構子新增了 make_current 關鍵字引數。

在 5.0 版更改: 預設使用 asyncio 事件迴圈。在 Python 3 上,除非冗餘地指定 asyncio 事件迴圈,否則無法使用 IOLoop.configure 方法。

在 6.3 版更改: 現在建立 IOLoop 時,預設值為 make_current=True - 之前預設值為如果沒有目前的事件迴圈,則將其設為目前的事件迴圈。

執行 IOLoop

static IOLoop.current() IOLoop[原始碼]
static IOLoop.current(instance: bool = True) Optional[IOLoop]

傳回目前執行緒的 IOLoop

如果 IOLoop 目前正在執行,或已由 make_current 標記為目前的,則傳回該實例。如果沒有目前的 IOLoopinstance 為 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 是很有用的,以便在啟動時執行的程式碼可以找到正確的實例。

變更於版本 4.1:在沒有 current IOLoop 時建立的 IOLoop 將自動成為 current。

變更於版本 5.0:此方法也會設定目前的 asyncio 事件迴圈。

自版本 6.2 起已棄用:透過 Tornado 設定和清除 current 事件迴圈已棄用。 如果您需要此功能,請改用 asyncio.set_event_loop

static IOLoop.clear_current() None[原始碼]

清除目前執行緒的 IOLoop

主要用於測試框架在測試之間使用。

變更於版本 5.0:此方法也會清除目前的 asyncio 事件迴圈。

自版本 6.2 起已棄用。

IOLoop.start() None[原始碼]

啟動 I/O 迴圈。

迴圈將會執行,直到其中一個回呼呼叫 stop(),這將使迴圈在目前的事件迭代完成後停止。

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.READIOLoop.WRITEIOLoop.ERROR 的位元 OR 運算。

當事件發生時,將執行 handler(fd, events)

在 4.0 版本變更: 新增了傳遞類檔案物件以及原始檔案描述符的功能。

IOLoop.update_handler(fd: Union[int, _Selectable], events: int) None[原始碼]

變更我們監聽 fd 的事件。

在 4.0 版本變更: 新增了傳遞類檔案物件以及原始檔案描述符的功能。

IOLoop.remove_handler(fd: Union[int, _Selectable]) None[原始碼]

停止監聽 fd 上的事件。

在 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_timeoutcall_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 中執行函式。如果 executorNone,則會使用 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 物件。

start() None[原始碼]

啟動計時器。

stop() None[原始碼]

停止計時器。

is_running() bool[原始碼]

如果此 PeriodicCallback 已啟動,則傳回 True

4.1 版本新增。