用于非阻塞套接字的 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
?。
一個 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)。
返回當(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)。
使其成為當(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)。
清除當(dāng)前線程的 ?IOLoop
?。
主要供測試框架在測試之間使用。
在 5.0 版更改: 此方法還清除當(dāng)前的 ?asyncio
事件循環(huán)。
啟動?I/O
? 循環(huán)。
循環(huán)將一直運(yùn)行,直到其中一個回調(diào)調(diào)用 ?stop()
?,這將使循環(huán)在當(dāng)前事件迭代完成后停止。
停止 ?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
?,運(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)
關(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
? 方法。
?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 版起已棄用。
不推薦使用 ?make_current()
? 的別名。
在 5.0 版更改: 以前,此方法將此 ?IOLoop
設(shè)置為?IOLoop.instance()
使用的全局單例。 現(xiàn)在 ?instance()
? 是 ?current()
? 的別名,?install()
? 是 ?make_current()
? 的別名。
自 5.0 版起已棄用。
不推薦使用 ?clear_current()
? 的別名。
在 5.0 版更改: 以前,此方法將清除 ?IOLoop.instance()
? 用作全局單例的 ?IOLoop
?。 現(xiàn)在 ?instance()
? 是 ?current()
? 的別名,?clear_instance()
? 是 ?clear_current()
? 的別名。
自 5.0 版起已棄用。
注冊給定的處理程序以接收fd
的給定事件。
?fd
?參數(shù)可以是整數(shù)文件描述符,也可以是具有 ?fileno()
? 和 ?close()
? 方法的類文件對象。
?events
參數(shù)是常量 ?IOLoop.READ
?、?IOLoop.WRITE
? 和 ?IOLoop.ERROR
? 的按位或。
當(dāng)事件發(fā)生時,將運(yùn)行 ?handler(fd, events)
?。
在 4.0 版更改: 除了原始文件描述符之外,還添加了傳遞類似文件的對象的能力。
改變我們監(jiān)聽?fd
?上的事件。
在 4.0 版更改: 除了原始文件描述符之外,還添加了傳遞類似文件的對象的能力。
停止監(jiān)聽fd
上的事件。
在 4.0 版更改: 除了原始文件描述符之外,還添加了傳遞類似文件的對象的能力。
在下一次 ?I/O
? 循環(huán)迭代中調(diào)用給定的回調(diào)。
任何時候從任何線程調(diào)用此方法都是安全的,信號處理程序除外。 請注意,這是 ?IOLoop
中唯一保證線程安全的方法; 與 ?IOLoop
的所有其他交互都必須從該 ?IOLoop
的線程中完成。 ?add_callback()
? 可用于控制從其他線程轉(zhuǎn)移到 ?IOLoop
的線程。
在下一次 ?I/O
? 循環(huán)迭代中調(diào)用給定的回調(diào)。
可從 Python 信號處理程序安全使用; 否則不應(yīng)使用。
當(dāng)給定的 ?Future
完成時,在 ?IOLoop
? 上安排回調(diào)。
使用一個參數(shù) ?Future
調(diào)用回調(diào)。
此方法僅接受 ?Future
對象而不接受其他可等待對象(與大多數(shù) Tornado 不同,兩者可互換)。
在 ?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)。
在 ?when
指定的絕對時間運(yùn)行?callback
?。
?when
必須是使用與 ?IOLoop.time
? 相同的參考點的數(shù)字。
返回一個不透明的句柄,可以傳遞給 ?remove_timeout
以取消。 注意,與同名的asyncio
方法不同,返回的對象沒有 ?cancel()
? 方法。
在?delay
?過去后運(yùn)行?callback
?。
返回一個不透明的句柄,可以傳遞給 ?remove_timeout
以取消。 注意,與同名的 ?asyncio
方法不同,返回的對象沒有 ?cancel()
? 方法。
取消掛起的超時。
參數(shù)是 ?add_timeout
返回的句柄。 即使回調(diào)已經(jīng)運(yùn)行,調(diào)用 ?remove_timeout
也是安全的。
在下一次 ?IOLoop
迭代中調(diào)用給定的回調(diào)。
從 Tornado 6.0 開始,此方法等效于 ?add_callback
?。
在 ?concurrent.futures.Executor
? 中運(yùn)行一個函數(shù)。 如果 ?executor
為 ?None
?,將使用 IOLoop默認(rèn)的 ?executor
?。
使用 ?functools.partial
? 將關(guān)鍵字參數(shù)傳遞給 ?func
?。
設(shè)置與 ?run_in_executor()
? 一起使用的默認(rèn)執(zhí)行程序。
根據(jù) ?IOLoop
的時鐘返回當(dāng)前時間。
返回值是相對于過去未指定時間的浮點數(shù)。
?IOLoop
可以定制為使用例如 ?time.monotonic
? 代替 ?time.time
?,但目前不支持此方法,因此此方法等效于 ?time.time
?
安排定期調(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ù)。
啟動計時器。
停止計時器。
如果此 ?PeriodicCallback
已啟動,則返回 ?True
?。
更多建議: