用于非阻塞套接字的 I/O 事件循环。
在 Tornado 6.0 中,IOLoop是 asyncio事件循环的包装器,由于历史原因,接口略有不同。 应用程序可以直接使用 IOLoop接口或底层asyncio事件循环(除非需要与旧版本的 Tornado 兼容,在这种情况下必须使用 IOLoop)。
典型的应用程序将使用单个 IOLoop对象,通过IOLoop.current类方法访问。IOLoop.start方法(或等效的 asyncio.AbstractEventLoop.run_forever)通常应在 main() 函数的末尾调用。 非典型应用程序可能使用多个 IOLoop,例如每个线程或每个单元测试用例一个 IOLoop。
一个 I/O 事件循环。
从 Tornado 6.0 开始,IOLoop是 asyncio事件循环的包装器。
简单 TCP 服务器的示例用法:
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()
默认情况下,新构建的 IOLoop成为线程的当前 IOLoop,除非已经存在当前 IOLoop。 此行为可以通过 IOLoop构造函数的make_current参数来控制:如果 make_current=True,新的 IOLoop将始终尝试成为当前实例,如果已经存在当前实例,则会引发错误。 如果 make_current=False,新的 IOLoop将不会尝试成为当前的。
一般来说,IOLoop不能在分叉中存活或以任何方式跨进程共享。 当使用多个进程时,每个进程都应该创建自己的 IOLoop,这也意味着任何依赖于 IOLoop的对象(例如 AsyncHTTPClient)也必须在子进程中创建。 作为指导,任何启动进程(包括 tornado.process 和 multiprocessing模块)都应该尽早启动,最好是应用程序在 main() 中加载其配置后首先执行的操作。
在 4.2 版更改: 向 IOLoop构造函数添加了 make_current关键字参数。
在 5.0 版更改: 默认使用 asyncio事件循环。 IOLoop.configure 方法不能在 Python 3 上使用,除非冗余指定 asyncio事件循环。
返回当前线程的 IOLoop。
如果 IOLoop当前正在运行或已被 make_current标记为当前,则返回instance。 如果没有当前 IOLoop并且instance为真,则创建一个。
在 4.1 版更改: 添加了实例参数来控制对 IOLoop.instance() 的回退。
在 5.0 版更改:在 Python 3 上,当前 IOLoop的控制权委托给 asyncio,并使用此方法和其他方法作为传递访问器。 instance参数现在控制在没有 IOLoop时是否自动创建,而不是我们是否回退到 IOLoop.instance() (现在是此方法的别名)。 instance=False 已弃用,因为即使我们不创建 IOLoop,此方法也可能会初始化 asyncio循环。
使其成为当前线程的 IOLoop。
IOLoop在启动时自动成为其线程的当前线程,但有时在启动 IOLoop之前显式调用 make_current很有用,以便在启动时运行的代码可以找到正确的实例。
在 4.1 版更改: 在没有当前 IOLoop时创建的 IOLoop将自动变为当前。
在 5.0 版更改: 此方法还设置当前的 asyncio事件循环。
清除当前线程的 IOLoop。
主要供测试框架在测试之间使用。
在 5.0 版更改: 此方法还清除当前的 asyncio事件循环。
启动I/O 循环。
循环将一直运行,直到其中一个回调调用 stop(),这将使循环在当前事件迭代完成后停止。
停止 I/O 循环。
如果事件循环当前未运行,则对 start() 的下一次调用将立即返回。
请注意,即使在调用 stop 之后,IOLoop也不会完全停止,直到 IOLoop.start 也返回。 在调用停止之前安排的一些工作可能在 IOLoop 关闭之前仍然运行。
启动 IOLoop,运行给定函数,然后停止循环。
该函数必须返回一个可等待对象或无。 如果函数返回一个可等待对象,IOLoop 将一直运行,直到解决了可等待对象(并且 run_sync() 将返回可等待对象的结果)。 如果引发异常,IOLoop将停止,异常将重新引发给调用者。
仅关键字参数 timeout 可用于设置函数的最大持续时间。 如果超时到期,则会引发 tornado.util.TimeoutError。
此方法对于允许在 main() 函数中进行异步调用很有用:
async def main():
# do stuff...
if __name__ == '__main__':
IOLoop.current().run_sync(main)
关闭 IOLoop,释放所有使用的资源。
如果 all_fds为真,则在 IOLoop上注册的所有文件描述符都将被关闭(不仅仅是 IOLoop本身创建的文件描述符)。
许多应用程序只会使用一个在整个进程生命周期内运行的 IOLoop。 在这种情况下,不需要关闭 IOLoop,因为当进程退出时,所有内容都会被清理。 IOLoop.close 主要用于单元测试等场景,创建和销毁大量的IOLoop。
IOLoop必须完全停止才能关闭。 这意味着在尝试调用 IOLoop.close() 之前必须调用 IOLoop.stop() 并且必须允许 IOLoop.start() 返回。 因此,close调用通常会出现在 start调用之后,而不是在 stop调用附近。
在 3.1 版更改:如果 IOLoop实现支持“文件描述符”的非整数对象,则当 all_fds为 true时,这些对象将具有其 close 方法。
IOLoop.current() 的已弃用别名。
在 5.0 版更改: 以前,此方法返回一个全局单例 IOLoop,与 current() 返回的每个线程 IOLoop 形成对比。 在几乎所有情况下,两者都是相同的(当它们不同时,它通常用于非 Tornado 线程与主线程的 IOLoop 进行通信)。 这种区别在 asyncio中不存在,因此为了便于与该包集成,instance() 已更改为 current() 的别名。 使用 instance() 的跨线程通信方面的应用程序应该将自己的全局变量设置为指向他们想要使用的 IOLoop。
自 5.0 版起已弃用。
不推荐使用 make_current() 的别名。
在 5.0 版更改: 以前,此方法将此 IOLoop设置为IOLoop.instance()使用的全局单例。 现在 instance() 是 current() 的别名,install() 是 make_current() 的别名。
自 5.0 版起已弃用。
不推荐使用 clear_current() 的别名。
在 5.0 版更改: 以前,此方法将清除 IOLoop.instance() 用作全局单例的 IOLoop。 现在 instance() 是 current() 的别名,clear_instance() 是 clear_current() 的别名。
自 5.0 版起已弃用。
注册给定的处理程序以接收fd的给定事件。
fd参数可以是整数文件描述符,也可以是具有 fileno() 和 close() 方法的类文件对象。
events参数是常量 IOLoop.READ、IOLoop.WRITE 和 IOLoop.ERROR 的按位或。
当事件发生时,将运行 handler(fd, events)。
在 4.0 版更改: 除了原始文件描述符之外,还添加了传递类似文件的对象的能力。
改变我们监听fd上的事件。
在 4.0 版更改: 除了原始文件描述符之外,还添加了传递类似文件的对象的能力。
停止监听fd上的事件。
在 4.0 版更改: 除了原始文件描述符之外,还添加了传递类似文件的对象的能力。
在下一次 I/O 循环迭代中调用给定的回调。
任何时候从任何线程调用此方法都是安全的,信号处理程序除外。 请注意,这是 IOLoop中唯一保证线程安全的方法; 与 IOLoop的所有其他交互都必须从该 IOLoop的线程中完成。 add_callback() 可用于控制从其他线程转移到 IOLoop的线程。
在下一次 I/O 循环迭代中调用给定的回调。
可从 Python 信号处理程序安全使用; 否则不应使用。
当给定的 Future完成时,在 IOLoop 上安排回调。
使用一个参数 Future调用回调。
此方法仅接受 Future对象而不接受其他可等待对象(与大多数 Tornado 不同,两者可互换)。
在 I/O 循环的时间截止日期运行回调。
返回一个不透明的句柄,可以传递给 remove_timeout以取消。
截止日期可以是一个表示时间的数字(与 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通常更容易实现,但是希望与 Tornado 4.0 之前的版本保持兼容性的子类必须使用 add_timeout代替。
在 4.0 版更改: 现在通过 *args 和 **kwargs 回调。
在 when指定的绝对时间运行callback。
when必须是使用与 IOLoop.time 相同的参考点的数字。
返回一个不透明的句柄,可以传递给 remove_timeout以取消。 注意,与同名的asyncio方法不同,返回的对象没有 cancel() 方法。
在delay过去后运行callback。
返回一个不透明的句柄,可以传递给 remove_timeout以取消。 注意,与同名的 asyncio方法不同,返回的对象没有 cancel() 方法。
取消挂起的超时。
参数是 add_timeout返回的句柄。 即使回调已经运行,调用 remove_timeout也是安全的。
在下一次 IOLoop迭代中调用给定的回调。
从 Tornado 6.0 开始,此方法等效于 add_callback。
在 concurrent.futures.Executor 中运行一个函数。 如果 executor为 None,将使用 IOLoop默认的 executor。
使用 functools.partial 将关键字参数传递给 func。
设置与 run_in_executor() 一起使用的默认执行程序。
根据 IOLoop的时钟返回当前时间。
返回值是相对于过去未指定时间的浮点数。
IOLoop可以定制为使用例如 time.monotonic 代替 time.time,但目前不支持此方法,因此此方法等效于 time.time
安排定期调用给定的回调。
每个callback_time毫秒调用一次回调。 请注意,超时以毫秒为单位,而 Tornado 中大多数其他与时间相关的函数使用秒。
如果指定了jitter,每个回调时间将在一个jitter * callback_time毫秒的窗口内随机选择。 抖动可用于减少具有相似周期的事件的对齐。 0.1 的抖动意味着允许 10% 的回调时间变化。 窗口以 callback_time 为中心,因此给定时间间隔内的调用总数不应受到添加抖动的显着影响。
如果回调运行时间超过 callback_time 毫秒,则将跳过后续调用以按计划返回。
start必须在 PeriodicCallback 创建后调用。
在 5.0 版中更改: io_loop参数(自 4.1 版以来已弃用)已被删除。
在 5.1 版更改: 添加了 jitter参数。
启动计时器。
停止计时器。
如果此 PeriodicCallback已启动,则返回 True。