Tornado 主事件循環(huán)

2022-03-10 10:17 更新

用于非阻塞套接字的 I/O 事件循環(huán)。

在 Tornado 6.0 中,?IOLoop是 ?asyncio事件循環(huán)的包裝器,由于歷史原因,接口略有不同。 應(yīng)用程序可以直接使用 ?IOLoop接口或底層?asyncio?事件循環(huán)(除非需要與舊版本的 Tornado 兼容,在這種情況下必須使用 ?IOLoop?)。

典型的應(yīng)用程序?qū)⑹褂脝蝹€ ?IOLoop對象,通過IOLoop.current類方法訪問。IOLoop.start方法(或等效的 ?asyncio.AbstractEventLoop.run_forever?)通常應(yīng)在 ?main()? 函數(shù)的末尾調(diào)用。 非典型應(yīng)用程序可能使用多個 ?IOLoop?,例如每個線程或每個單元測試用例一個 ?IOLoop?。

IOLoop 對象

class tornado.ioloop.IOLoop

一個 I/O 事件循環(huán)。

從 Tornado 6.0 開始,?IOLoop是 ?asyncio事件循環(huán)的包裝器。

簡單 TCP 服務(wù)器的示例用法:

import errno
import functools
import socket

import tornado.ioloop
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)

if __name__ == '__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)
    io_loop.start()

默認(rèn)情況下,新構(gòu)建的 ?IOLoop成為線程的當(dāng)前 ?IOLoop?,除非已經(jīng)存在當(dāng)前 ?IOLoop?。 此行為可以通過 ?IOLoop構(gòu)造函數(shù)的make_current參數(shù)來控制:如果 ?make_current=True?,新的 ?IOLoop將始終嘗試成為當(dāng)前實例,如果已經(jīng)存在當(dāng)前實例,則會引發(fā)錯誤。 如果 ?make_current=False?,新的 ?IOLoop將不會嘗試成為當(dāng)前的。

一般來說,?IOLoop不能在分叉中存活或以任何方式跨進(jìn)程共享。 當(dāng)使用多個進(jìn)程時,每個進(jìn)程都應(yīng)該創(chuàng)建自己的 ?IOLoop?,這也意味著任何依賴于 ?IOLoop的對象(例如 ?AsyncHTTPClient?)也必須在子進(jìn)程中創(chuàng)建。 作為指導(dǎo),任何啟動進(jìn)程(包括 ?tornado.process? 和 ?multiprocessing模塊)都應(yīng)該盡早啟動,最好是應(yīng)用程序在 ?main()? 中加載其配置后首先執(zhí)行的操作。

在 4.2 版更改: 向 ?IOLoop構(gòu)造函數(shù)添加了 ?make_current關(guān)鍵字參數(shù)。

在 5.0 版更改: 默認(rèn)使用 ?asyncio事件循環(huán)。 ?IOLoop.configure? 方法不能在 Python 3 上使用,除非冗余指定 ?asyncio事件循環(huán)。

運(yùn)行IOLoop

static IOLoop.current(instance: bool = True) → Optional[tornado.ioloop.IOLoop]

返回當(dāng)前線程的 ?IOLoop?。

如果 ?IOLoop當(dāng)前正在運(yùn)行或已被 ?make_current標(biāo)記為當(dāng)前,則返回?instance?。 如果沒有當(dāng)前 ?IOLoop并且?instance?為真,則創(chuàng)建一個。

在 4.1 版更改: 添加了實例參數(shù)來控制對 ?IOLoop.instance()? 的回退。

在 5.0 版更改:在 Python 3 上,當(dāng)前 ?IOLoop的控制權(quán)委托給 ?asyncio?,并使用此方法和其他方法作為傳遞訪問器。 ?instance參數(shù)現(xiàn)在控制在沒有 ?IOLoop時是否自動創(chuàng)建,而不是我們是否回退到 ?IOLoop.instance()? (現(xiàn)在是此方法的別名)。 ?instance=False? 已棄用,因為即使我們不創(chuàng)建 ?IOLoop?,此方法也可能會初始化 ?asyncio循環(huán)。

IOLoop.make_current() → None

使其成為當(dāng)前線程的 ?IOLoop?。

?IOLoop在啟動時自動成為其線程的當(dāng)前線程,但有時在啟動 ?IOLoop之前顯式調(diào)用 ?make_current很有用,以便在啟動時運(yùn)行的代碼可以找到正確的實例。

在 4.1 版更改: 在沒有當(dāng)前 ?IOLoop時創(chuàng)建的 ?IOLoop將自動變?yōu)楫?dāng)前。

在 5.0 版更改: 此方法還設(shè)置當(dāng)前的 ?asyncio事件循環(huán)。

static IOLoop.clear_current() → None

清除當(dāng)前線程的 ?IOLoop?。

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

在 5.0 版更改: 此方法還清除當(dāng)前的 ?asyncio事件循環(huán)。

IOLoop.start() → None

啟動?I/O? 循環(huán)。

循環(huán)將一直運(yùn)行,直到其中一個回調(diào)調(diào)用 ?stop()?,這將使循環(huán)在當(dāng)前事件迭代完成后停止。

IOLoop.stop() → None

停止 ?I/O? 循環(huán)。

如果事件循環(huán)當(dāng)前未運(yùn)行,則對 ?start()? 的下一次調(diào)用將立即返回。

請注意,即使在調(diào)用 ?stop ?之后,?IOLoop也不會完全停止,直到 ?IOLoop.start? 也返回。 在調(diào)用停止之前安排的一些工作可能在 ?IOLoop? 關(guān)閉之前仍然運(yùn)行。

IOLoop.run_sync(func: Callable, timeout: Optional[float] = None) → Any

啟動 ?IOLoop?,運(yùn)行給定函數(shù),然后停止循環(huán)。

該函數(shù)必須返回一個可等待對象或無。 如果函數(shù)返回一個可等待對象,?IOLoop? 將一直運(yùn)行,直到解決了可等待對象(并且 ?run_sync()? 將返回可等待對象的結(jié)果)。 如果引發(fā)異常,?IOLoop將停止,異常將重新引發(fā)給調(diào)用者。

僅關(guān)鍵字參數(shù) ?timeout? 可用于設(shè)置函數(shù)的最大持續(xù)時間。 如果超時到期,則會引發(fā) ?tornado.util.TimeoutError?。

此方法對于允許在 ?main()? 函數(shù)中進(jìn)行異步調(diào)用很有用:

async def main():
    # do stuff...

if __name__ == '__main__':
    IOLoop.current().run_sync(main)

IOLoop.close(all_fds: bool = False) → None

關(guān)閉 ?IOLoop?,釋放所有使用的資源。

如果 ?all_fds為真,則在 ?IOLoop上注冊的所有文件描述符都將被關(guān)閉(不僅僅是 ?IOLoop本身創(chuàng)建的文件描述符)。

許多應(yīng)用程序只會使用一個在整個進(jìn)程生命周期內(nèi)運(yùn)行的 ?IOLoop?。 在這種情況下,不需要關(guān)閉 ?IOLoop?,因為當(dāng)進(jìn)程退出時,所有內(nèi)容都會被清理。 ?IOLoop.close? 主要用于單元測試等場景,創(chuàng)建和銷毀大量的?IOLoop?。

?IOLoop必須完全停止才能關(guān)閉。 這意味著在嘗試調(diào)用 ?IOLoop.close()? 之前必須調(diào)用 ?IOLoop.stop()? 并且必須允許 ?IOLoop.start()? 返回。 因此,?close調(diào)用通常會出現(xiàn)在 ?start調(diào)用之后,而不是在 ?stop調(diào)用附近。

在 3.1 版更改:如果 ?IOLoop實現(xiàn)支持“文件描述符”的非整數(shù)對象,則當(dāng) ?all_fds為 ?true時,這些對象將具有其 ?close? 方法。

static IOLoop.instance() → tornado.ioloop.IOLoop

?IOLoop.current()? 的已棄用別名。

在 5.0 版更改: 以前,此方法返回一個全局單例 ?IOLoop?,與 ?current()? 返回的每個線程 ?IOLoop? 形成對比。 在幾乎所有情況下,兩者都是相同的(當(dāng)它們不同時,它通常用于非 Tornado 線程與主線程的 ?IOLoop ?進(jìn)行通信)。 這種區(qū)別在 ?asyncio中不存在,因此為了便于與該包集成,?instance()? 已更改為 ?current()? 的別名。 使用 ?instance()? 的跨線程通信方面的應(yīng)用程序應(yīng)該將自己的全局變量設(shè)置為指向他們想要使用的 ?IOLoop?。

自 5.0 版起已棄用。

IOLoop.install() → None

不推薦使用 ?make_current()? 的別名。

在 5.0 版更改: 以前,此方法將此 ?IOLoop設(shè)置為?IOLoop.instance()使用的全局單例。 現(xiàn)在 ?instance()? 是 ?current()? 的別名,?install()? 是 ?make_current()? 的別名。

自 5.0 版起已棄用。

static IOLoop.clear_instance() → None

不推薦使用 ?clear_current()? 的別名。

在 5.0 版更改: 以前,此方法將清除 ?IOLoop.instance()? 用作全局單例的 ?IOLoop?。 現(xiàn)在 ?instance()? 是 ?current()? 的別名,?clear_instance()? 是 ?clear_current()? 的別名。

自 5.0 版起已棄用。

I/O事件

IOLoop.add_handler(fd: Union[int, tornado.ioloop._Selectable], handler: Callable[[...], None], events: int) → None

注冊給定的處理程序以接收fd的給定事件。

?fd?參數(shù)可以是整數(shù)文件描述符,也可以是具有 ?fileno()? 和 ?close()? 方法的類文件對象。

?events參數(shù)是常量 ?IOLoop.READ?、?IOLoop.WRITE? 和 ?IOLoop.ERROR? 的按位或。

當(dāng)事件發(fā)生時,將運(yùn)行 ?handler(fd, events)?。

在 4.0 版更改: 除了原始文件描述符之外,還添加了傳遞類似文件的對象的能力。

IOLoop.update_handler(fd: Union[int, tornado.ioloop._Selectable], events: int) → None

改變我們監(jiān)聽?fd?上的事件。

在 4.0 版更改: 除了原始文件描述符之外,還添加了傳遞類似文件的對象的能力。

IOLoop.remove_handler(fd: Union[int, tornado.ioloop._Selectable]) → None

停止監(jiān)聽fd上的事件。

在 4.0 版更改: 除了原始文件描述符之外,還添加了傳遞類似文件的對象的能力。

回調(diào)和超時

IOLoop.add_callback(callback: Callable, *args, **kwargs) → None

在下一次 ?I/O? 循環(huán)迭代中調(diào)用給定的回調(diào)。

任何時候從任何線程調(diào)用此方法都是安全的,信號處理程序除外。 請注意,這是 ?IOLoop中唯一保證線程安全的方法; 與 ?IOLoop的所有其他交互都必須從該 ?IOLoop的線程中完成。 ?add_callback()? 可用于控制從其他線程轉(zhuǎn)移到 ?IOLoop的線程。

IOLoop.add_callback_from_signal(callback: Callable, *args, **kwargs) → None

在下一次 ?I/O? 循環(huán)迭代中調(diào)用給定的回調(diào)。

可從 Python 信號處理程序安全使用; 否則不應(yīng)使用。

IOLoop.add_future(future: Union[Future[_T], concurrent.futures.Future[_T]], callback: Callable[[Future[_T]], None]) → None

當(dāng)給定的 ?Future完成時,在 ?IOLoop? 上安排回調(diào)。

使用一個參數(shù) ?Future調(diào)用回調(diào)。

此方法僅接受 ?Future對象而不接受其他可等待對象(與大多數(shù) Tornado 不同,兩者可互換)。

IOLoop.add_timeout(deadline: Union[float, datetime.timedelta], callback: Callable[[...], None], *args, **kwargs) → object

在 ?I/O? 循環(huán)的時間截止日期運(yùn)行回調(diào)。

返回一個不透明的句柄,可以傳遞給 ?remove_timeout以取消。

截止日期可以是一個表示時間的數(shù)字(與 ?IOLoop.time? 的比例相同,通常是 ?time.time?),或者是相對于當(dāng)前時間的截止日期的 ?datetime.timedelta? 對象。 從 Tornado 4.0 開始, ?call_later是相對情況下更方便的替代方案,因為它不需要 ?timedelta對象。

請注意,從其他線程調(diào)用 ?add_timeout是不安全的。 相反,您必須使用 ?add_callback將控制權(quán)轉(zhuǎn)移到 ?IOLoop的線程,然后從那里調(diào)用 ?add_timeout

?IOLoop的子類必須實現(xiàn) ?add_timeout或 ?call_at?; 每個的默認(rèn)實現(xiàn)將調(diào)用另一個。 ?call_at通常更容易實現(xiàn),但是希望與 Tornado 4.0 之前的版本保持兼容性的子類必須使用 ?add_timeout代替。

在 4.0 版更改: 現(xiàn)在通過 *args 和 **kwargs 回調(diào)。

IOLoop.call_at(when: float, callback: Callable[[...], None], *args, **kwargs) → object

在 ?when指定的絕對時間運(yùn)行?callback?。

?when必須是使用與 ?IOLoop.time? 相同的參考點的數(shù)字。

返回一個不透明的句柄,可以傳遞給 ?remove_timeout以取消。 注意,與同名的asyncio方法不同,返回的對象沒有 ?cancel()? 方法。

IOLoop.call_later(delay: float, callback: Callable[[...], None], *args, **kwargs) → object

在?delay?過去后運(yùn)行?callback?。

返回一個不透明的句柄,可以傳遞給 ?remove_timeout以取消。 注意,與同名的 ?asyncio方法不同,返回的對象沒有 ?cancel()? 方法。

IOLoop.remove_timeout(timeout: object) → None

取消掛起的超時。

參數(shù)是 ?add_timeout返回的句柄。 即使回調(diào)已經(jīng)運(yùn)行,調(diào)用 ?remove_timeout也是安全的。

IOLoop.spawn_callback(callback: Callable, *args, **kwargs) → None

在下一次 ?IOLoop迭代中調(diào)用給定的回調(diào)。

從 Tornado 6.0 開始,此方法等效于 ?add_callback?。

IOLoop.run_in_executor(executor: Optional[concurrent.futures._base.Executor], func: Callable[[...], _T], *args) → Awaitable[_T]

在 ?concurrent.futures.Executor? 中運(yùn)行一個函數(shù)。 如果 ?executor為 ?None?,將使用 IOLoop默認(rèn)的 ?executor?。

使用 ?functools.partial? 將關(guān)鍵字參數(shù)傳遞給 ?func?。

IOLoop.set_default_executor(executor: concurrent.futures._base.Executor) → None

設(shè)置與 ?run_in_executor()? 一起使用的默認(rèn)執(zhí)行程序。

IOLoop.time() → float

根據(jù) ?IOLoop的時鐘返回當(dāng)前時間。

返回值是相對于過去未指定時間的浮點數(shù)。

?IOLoop可以定制為使用例如 ?time.monotonic? 代替 ?time.time?,但目前不支持此方法,因此此方法等效于 ?time.time?

class tornado.ioloop.PeriodicCallback(callback: Callable[[], None], callback_time: float, jitter: float = 0)。

安排定期調(diào)用給定的回調(diào)。

每個?callback_time毫秒調(diào)用一次回調(diào)。 請注意,超時以毫秒為單位,而 Tornado 中大多數(shù)其他與時間相關(guān)的函數(shù)使用秒。

如果指定了?jitter?,每個回調(diào)時間將在一個?jitter * callback_time?毫秒的窗口內(nèi)隨機(jī)選擇。 抖動可用于減少具有相似周期的事件的對齊。 0.1 的抖動意味著允許 10% 的回調(diào)時間變化。 窗口以 ?callback_time? 為中心,因此給定時間間隔內(nèi)的調(diào)用總數(shù)不應(yīng)受到添加抖動的顯著影響。

如果回調(diào)運(yùn)行時間超過 ?callback_time? 毫秒,則將跳過后續(xù)調(diào)用以按計劃返回。

?start必須在 ?PeriodicCallback? 創(chuàng)建后調(diào)用。

在 5.0 版中更改: ?io_loop參數(shù)(自 4.1 版以來已棄用)已被刪除。

在 5.1 版更改: 添加了 ?jitter參數(shù)。

start() → None

啟動計時器。

stop() → None

停止計時器。

is_running() → bool

如果此 ?PeriodicCallback已啟動,則返回 ?True?。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號