用于非阻塞套接字的 I/O 事件循環(huán)。
在 Tornado 6.0 中,?IOLoop
是 ?asyncio
事件循環(huán)的包裝器,由于歷史原因,接口略有不同。 應(yīng)用程序可以直接使用 ?IOLoop
接口或底層?asyncio
?事件循環(huán)(除非需要與舊版本的 Tornado 兼容,在這種情況下必須使用 ?IOLoop
?)。
典型的應(yīng)用程序?qū)⑹褂脝蝹€(gè) ?IOLoop
對(duì)象,通過IOLoop.current
類方法訪問。IOLoop.start
方法(或等效的 ?asyncio.AbstractEventLoop.run_forever
?)通常應(yīng)在 ?main()
? 函數(shù)的末尾調(diào)用。 非典型應(yīng)用程序可能使用多個(gè) ?IOLoop
?,例如每個(gè)線程或每個(gè)單元測(cè)試用例一個(gè) ?IOLoop
?。
一個(gè) 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)前實(shí)例,如果已經(jīng)存在當(dāng)前實(shí)例,則會(huì)引發(fā)錯(cuò)誤。 如果 ?make_current=False
?,新的 ?IOLoop
將不會(huì)嘗試成為當(dāng)前的。
一般來說,?IOLoop
不能在分叉中存活或以任何方式跨進(jìn)程共享。 當(dāng)使用多個(gè)進(jìn)程時(shí),每個(gè)進(jìn)程都應(yīng)該創(chuàng)建自己的 ?IOLoop
?,這也意味著任何依賴于 ?IOLoop
的對(duì)象(例如 ?AsyncHTTPClient
?)也必須在子進(jìn)程中創(chuàng)建。 作為指導(dǎo),任何啟動(dòng)進(jìn)程(包括 ?tornado.process
? 和 ?multiprocessing
模塊)都應(yīng)該盡早啟動(dò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)建一個(gè)。
在 4.1 版更改: 添加了實(shí)例參數(shù)來控制對(duì) ?IOLoop.instance()
? 的回退。
在 5.0 版更改:在 Python 3 上,當(dāng)前 ?IOLoop
的控制權(quán)委托給 ?asyncio
?,并使用此方法和其他方法作為傳遞訪問器。 ?instance
參數(shù)現(xiàn)在控制在沒有 ?IOLoop
時(shí)是否自動(dòng)創(chuàng)建,而不是我們是否回退到 ?IOLoop.instance()
? (現(xiàn)在是此方法的別名)。 ?instance=False
? 已棄用,因?yàn)榧词刮覀儾粍?chuàng)建 ?IOLoop
?,此方法也可能會(huì)初始化 ?asyncio
循環(huán)。
使其成為當(dāng)前線程的 ?IOLoop
?。
?IOLoop
在啟動(dòng)時(shí)自動(dòng)成為其線程的當(dāng)前線程,但有時(shí)在啟動(dòng) ?IOLoop
之前顯式調(diào)用 ?make_current
很有用,以便在啟動(dòng)時(shí)運(yùn)行的代碼可以找到正確的實(shí)例。
在 4.1 版更改: 在沒有當(dāng)前 ?IOLoop
時(shí)創(chuàng)建的 ?IOLoop
將自動(dòng)變?yōu)楫?dāng)前。
在 5.0 版更改: 此方法還設(shè)置當(dāng)前的 ?asyncio
事件循環(huán)。
清除當(dāng)前線程的 ?IOLoop
?。
主要供測(cè)試框架在測(cè)試之間使用。
在 5.0 版更改: 此方法還清除當(dāng)前的 ?asyncio
事件循環(huán)。
啟動(dòng)?I/O
? 循環(huán)。
循環(huán)將一直運(yùn)行,直到其中一個(gè)回調(diào)調(diào)用 ?stop()
?,這將使循環(huán)在當(dāng)前事件迭代完成后停止。
停止 ?I/O
? 循環(huán)。
如果事件循環(huán)當(dāng)前未運(yùn)行,則對(duì) ?start()
? 的下一次調(diào)用將立即返回。
請(qǐng)注意,即使在調(diào)用 ?stop
?之后,?IOLoop
也不會(huì)完全停止,直到 ?IOLoop.start
? 也返回。 在調(diào)用停止之前安排的一些工作可能在 ?IOLoop
? 關(guān)閉之前仍然運(yùn)行。
啟動(dòng) ?IOLoop
?,運(yùn)行給定函數(shù),然后停止循環(huán)。
該函數(shù)必須返回一個(gè)可等待對(duì)象或無。 如果函數(shù)返回一個(gè)可等待對(duì)象,?IOLoop
? 將一直運(yùn)行,直到解決了可等待對(duì)象(并且 ?run_sync()
? 將返回可等待對(duì)象的結(jié)果)。 如果引發(fā)異常,?IOLoop
將停止,異常將重新引發(fā)給調(diào)用者。
僅關(guān)鍵字參數(shù) ?timeout
? 可用于設(shè)置函數(shù)的最大持續(xù)時(shí)間。 如果超時(shí)到期,則會(huì)引發(fā) ?tornado.util.TimeoutError
?。
此方法對(duì)于允許在 ?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
上注冊(cè)的所有文件描述符都將被關(guān)閉(不僅僅是 ?IOLoop
本身創(chuàng)建的文件描述符)。
許多應(yīng)用程序只會(huì)使用一個(gè)在整個(gè)進(jìn)程生命周期內(nèi)運(yùn)行的 ?IOLoop
?。 在這種情況下,不需要關(guān)閉 ?IOLoop
?,因?yàn)楫?dāng)進(jìn)程退出時(shí),所有內(nèi)容都會(huì)被清理。 ?IOLoop.close
? 主要用于單元測(cè)試等場景,創(chuàng)建和銷毀大量的?IOLoop
?。
?IOLoop
必須完全停止才能關(guān)閉。 這意味著在嘗試調(diào)用 ?IOLoop.close()
? 之前必須調(diào)用 ?IOLoop.stop()
? 并且必須允許 ?IOLoop.start()
? 返回。 因此,?close
調(diào)用通常會(huì)出現(xiàn)在 ?start
調(diào)用之后,而不是在 ?stop
調(diào)用附近。
在 3.1 版更改:如果 ?IOLoop
實(shí)現(xiàn)支持“文件描述符”的非整數(shù)對(duì)象,則當(dāng) ?all_fds
為 ?true
時(shí),這些對(duì)象將具有其 ?close
? 方法。
?IOLoop.current()
? 的已棄用別名。
在 5.0 版更改: 以前,此方法返回一個(gè)全局單例 ?IOLoop
?,與 ?current()
? 返回的每個(gè)線程 ?IOLoop
? 形成對(duì)比。 在幾乎所有情況下,兩者都是相同的(當(dāng)它們不同時(shí),它通常用于非 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 版起已棄用。
注冊(cè)給定的處理程序以接收fd
的給定事件。
?fd
?參數(shù)可以是整數(shù)文件描述符,也可以是具有 ?fileno()
? 和 ?close()
? 方法的類文件對(duì)象。
?events
參數(shù)是常量 ?IOLoop.READ
?、?IOLoop.WRITE
? 和 ?IOLoop.ERROR
? 的按位或。
當(dāng)事件發(fā)生時(shí),將運(yùn)行 ?handler(fd, events)
?。
在 4.0 版更改: 除了原始文件描述符之外,還添加了傳遞類似文件的對(duì)象的能力。
改變我們監(jiān)聽?fd
?上的事件。
在 4.0 版更改: 除了原始文件描述符之外,還添加了傳遞類似文件的對(duì)象的能力。
停止監(jiān)聽fd
上的事件。
在 4.0 版更改: 除了原始文件描述符之外,還添加了傳遞類似文件的對(duì)象的能力。
在下一次 ?I/O
? 循環(huán)迭代中調(diào)用給定的回調(diào)。
任何時(shí)候從任何線程調(diào)用此方法都是安全的,信號(hào)處理程序除外。 請(qǐng)注意,這是 ?IOLoop
中唯一保證線程安全的方法; 與 ?IOLoop
的所有其他交互都必須從該 ?IOLoop
的線程中完成。 ?add_callback()
? 可用于控制從其他線程轉(zhuǎn)移到 ?IOLoop
的線程。
在下一次 ?I/O
? 循環(huán)迭代中調(diào)用給定的回調(diào)。
可從 Python 信號(hào)處理程序安全使用; 否則不應(yīng)使用。
當(dāng)給定的 ?Future
完成時(shí),在 ?IOLoop
? 上安排回調(diào)。
使用一個(gè)參數(shù) ?Future
調(diào)用回調(diào)。
此方法僅接受 ?Future
對(duì)象而不接受其他可等待對(duì)象(與大多數(shù) Tornado 不同,兩者可互換)。
在 ?I/O
? 循環(huán)的時(shí)間截止日期運(yùn)行回調(diào)。
返回一個(gè)不透明的句柄,可以傳遞給 ?remove_timeout
以取消。
截止日期可以是一個(gè)表示時(shí)間的數(shù)字(與 ?IOLoop.time
? 的比例相同,通常是 ?time.time
?),或者是相對(duì)于當(dāng)前時(shí)間的截止日期的 ?datetime.timedelta
? 對(duì)象。 從 Tornado 4.0 開始, ?call_later
是相對(duì)情況下更方便的替代方案,因?yàn)樗恍枰?nbsp;?timedelta
對(duì)象。
請(qǐng)注意,從其他線程調(diào)用 ?add_timeout
是不安全的。 相反,您必須使用 ?add_callback
將控制權(quán)轉(zhuǎn)移到 ?IOLoop
的線程,然后從那里調(diào)用 ?add_timeout
。
?IOLoop
的子類必須實(shí)現(xiàn) ?add_timeout
或 ?call_at
?; 每個(gè)的默認(rèn)實(shí)現(xiàn)將調(diào)用另一個(gè)。 ?call_at
通常更容易實(shí)現(xiàn),但是希望與 Tornado 4.0 之前的版本保持兼容性的子類必須使用 ?add_timeout
代替。
在 4.0 版更改: 現(xiàn)在通過 *args 和 **kwargs 回調(diào)。
在 ?when
指定的絕對(duì)時(shí)間運(yùn)行?callback
?。
?when
必須是使用與 ?IOLoop.time
? 相同的參考點(diǎn)的數(shù)字。
返回一個(gè)不透明的句柄,可以傳遞給 ?remove_timeout
以取消。 注意,與同名的asyncio
方法不同,返回的對(duì)象沒有 ?cancel()
? 方法。
在?delay
?過去后運(yùn)行?callback
?。
返回一個(gè)不透明的句柄,可以傳遞給 ?remove_timeout
以取消。 注意,與同名的 ?asyncio
方法不同,返回的對(duì)象沒有 ?cancel()
? 方法。
取消掛起的超時(shí)。
參數(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)行一個(gè)函數(shù)。 如果 ?executor
為 ?None
?,將使用 IOLoop默認(rèn)的 ?executor
?。
使用 ?functools.partial
? 將關(guān)鍵字參數(shù)傳遞給 ?func
?。
設(shè)置與 ?run_in_executor()
? 一起使用的默認(rèn)執(zhí)行程序。
根據(jù) ?IOLoop
的時(shí)鐘返回當(dāng)前時(shí)間。
返回值是相對(duì)于過去未指定時(shí)間的浮點(diǎn)數(shù)。
?IOLoop
可以定制為使用例如 ?time.monotonic
? 代替 ?time.time
?,但目前不支持此方法,因此此方法等效于 ?time.time
?
安排定期調(diào)用給定的回調(diào)。
每個(gè)?callback_time
毫秒調(diào)用一次回調(diào)。 請(qǐng)注意,超時(shí)以毫秒為單位,而 Tornado 中大多數(shù)其他與時(shí)間相關(guān)的函數(shù)使用秒。
如果指定了?jitter
?,每個(gè)回調(diào)時(shí)間將在一個(gè)?jitter * callback_time
?毫秒的窗口內(nèi)隨機(jī)選擇。 抖動(dòng)可用于減少具有相似周期的事件的對(duì)齊。 0.1 的抖動(dòng)意味著允許 10% 的回調(diào)時(shí)間變化。 窗口以 ?callback_time
? 為中心,因此給定時(shí)間間隔內(nèi)的調(diào)用總數(shù)不應(yīng)受到添加抖動(dòng)的顯著影響。
如果回調(diào)運(yùn)行時(shí)間超過 ?callback_time
? 毫秒,則將跳過后續(xù)調(diào)用以按計(jì)劃返回。
?start
必須在 ?PeriodicCallback
? 創(chuàng)建后調(diào)用。
在 5.0 版中更改: ?io_loop
參數(shù)(自 4.1 版以來已棄用)已被刪除。
在 5.1 版更改: 添加了 ?jitter
參數(shù)。
啟動(dòng)計(jì)時(shí)器。
停止計(jì)時(shí)器。
如果此 ?PeriodicCallback
已啟動(dòng),則返回 ?True
?。
更多建議: