tornado.ioloop — 主事件循环¶
用于非阻塞套接字的 I/O 事件循环。
在 Tornado 6.0 中,IOLoop 是 asyncio 事件循环的包装器,具有略微不同的接口。 IOLoop 接口现在主要用于向后兼容性;新代码通常应该直接使用 asyncio 事件循环接口。 IOLoop.current 类方法提供了对应于正在运行的 asyncio 事件循环的 IOLoop 实例。
IOLoop 对象¶
- class tornado.ioloop.IOLoop(*args: Any, **kwargs: Any)[source]¶
- 一个 I/O 事件循环。 - 从 Tornado 6.0 开始, - IOLoop是- asyncio事件循环的包装器。- 简单 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.process和- multiprocessing模块)应该尽早执行,理想情况下是应用程序在加载其配置后执行的第一件事,并且在任何调用- IOLoop.start或- asyncio.run之前执行。- 在版本 4.2 中变更: 在 - IOLoop构造函数中添加了- make_current关键字参数。- 在版本 6.3 中变更: - make_current=True现在是创建 IOLoop 时默认的 - 以前默认是在没有当前事件循环的情况下将其设置为当前事件循环。
运行 IOLoop¶
- static IOLoop.current() IOLoop[source]¶
- static IOLoop.current(instance: bool = True) Optional[IOLoop]
- 返回当前线程的 - IOLoop。- 如果 - IOLoop正在运行或已通过- make_current标记为当前,则返回该实例。如果没有当前- IOLoop并且- instance为 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[source]¶
- 使当前线程使用此 - IOLoop。- 当 - IOLoop启动时,它会自动成为其线程的当前循环,但有时在启动- IOLoop之前显式调用- make_current会很有用,这样启动时运行的代码就可以找到正确的实例。- 版本 5.0 中变更: 此方法还会设置当前的 - asyncio事件循环。- 版本 6.2 起弃用: 通过 Tornado 设置和清除当前事件循环已弃用。如果您需要此功能,请改用 - asyncio.set_event_loop。
- static IOLoop.clear_current() None[source]¶
- 清除当前线程的 - IOLoop。- 主要供测试框架在测试之间使用。 - 版本 5.0 中变更: 此方法还会清除当前的 - asyncio事件循环。- 版本 6.2 起弃用。 
- IOLoop.stop() None[source]¶
- 停止 I/O 循环。 - 如果事件循环当前没有运行,则下次调用 - start()将立即返回。- 请注意,即使在调用 - stop后,- IOLoop也不会完全停止,直到- IOLoop.start也返回。在调用- stop之前安排的一些工作可能仍会在- IOLoop关闭之前运行。
- IOLoop.run_sync(func: Callable, timeout: Optional[float] = None) Any[source]¶
- 启动 - 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[source]¶
- 关闭 - IOLoop,释放使用的任何资源。- 如果 - all_fds为真,则将关闭在 IOLoop 上注册的所有文件描述符(不仅仅是- IOLoop本身创建的描述符)。- 许多应用程序只会使用一个 - IOLoop,该循环在整个进程的生命周期中运行。在这种情况下,无需关闭- IOLoop,因为所有内容都将在进程退出时清理。- IOLoop.close主要用于单元测试等场景,这些场景会创建和销毁大量的- IOLoops。- 必须完全停止 - IOLoop才能关闭它。这意味着必须调用- IOLoop.stop(),并且必须允许- IOLoop.start()返回,然后才能尝试调用- IOLoop.close()。因此,调用- close通常会出现在调用- start之后,而不是在调用- stop附近。- 版本 3.1 中变更: 如果 - IOLoop实现支持将非整数对象用作“文件描述符”,那么当- all_fds为真时,这些对象将调用其- close方法。
- static IOLoop.instance() IOLoop[source]¶
- IOLoop.current()的已弃用别名。- 在版本 5.0 中变更: 以前,此方法返回一个全局单例 - IOLoop,与- current()返回的每个线程- IOLoop相反。在几乎所有情况下,两者都是相同的(当它们不同时,通常用于从非 Tornado 线程通信回主线程的- IOLoop)。- asyncio中不存在这种区别,因此为了便于与该包的集成,- instance()已更改为- current()的别名。使用- instance()的跨线程通信方面的应用程序应改为将自己的全局变量设置为指向他们想要使用的- IOLoop。- 自版本 5.0 起已弃用。 
- IOLoop.install() None[source]¶
- make_current()的已弃用别名。- 在版本 5.0 中变更: 以前,此方法会将此 - IOLoop设置为- IOLoop.instance()使用的全局单例。现在- instance()是- current()的别名,- install()是- make_current()的别名。- 自版本 5.0 起已弃用。 
- static IOLoop.clear_instance() None[source]¶
- clear_current()的已弃用别名。- 在版本 5.0 中变更: 以前,此方法会清除 - IOLoop,该- 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[source]¶
- IOLoop.add_handler(fd: _S, handler: Callable[[_S, int], None], events: int) None
- 注册给定的处理程序以接收 - fd的给定事件。- fd参数可以是整数文件描述符,也可以是具有- fileno()和- close()方法的文件类对象。- events参数是常量- IOLoop.READ、- IOLoop.WRITE和- IOLoop.ERROR的按位或。- 当事件发生时,将运行 - handler(fd, events)。- 在版本 4.0 中变更: 添加了除了原始文件描述符之外还可以传递文件类对象的功能。 
回调和超时¶
- IOLoop.add_callback(callback: Callable, *args: Any, **kwargs: Any) None[source]¶
- 在下一次 I/O 循环迭代中调用给定的回调。 - 可以从任何线程在任何时间调用此方法,除了信号处理程序。注意,这是 - IOLoop中唯一保证线程安全的方法;与- IOLoop的所有其他交互都必须在该- IOLoop的线程中完成。- add_callback()可用于将控制权从其他线程转移到- IOLoop的线程。
- IOLoop.add_callback_from_signal(callback: Callable, *args: Any, **kwargs: Any) None[source]¶
- 在下一次 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[source]¶
- 在给定的 - Future完成时,在- IOLoop上调度一个回调。- 回调使用一个参数调用,即 - Future。- 此方法只接受 - Future对象,而不是其他可等待对象(与 Tornado 中大多数情况下两者可以互换不同)。
- IOLoop.add_timeout(deadline: Union[float, timedelta], callback: Callable, *args: Any, **kwargs: Any) object[source]¶
- 在 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_timeout或- call_at;每种方法的默认实现将调用另一种方法。- call_at通常更容易实现,但希望与 Tornado 4.0 之前的版本保持兼容的子类必须使用- add_timeout而不是它。- 版本 4.0 中的更改: 现在将 - *args和- **kwargs传递给回调。
- IOLoop.call_at(when: float, callback: Callable, *args: Any, **kwargs: Any) object[source]¶
- 在由 - when指定的绝对时间运行- callback。- when必须是一个使用与- IOLoop.time相同参考点的数字。- 返回一个不透明的句柄,可以传递给 - remove_timeout以取消。请注意,与- asyncio中同名方法不同,返回的对象没有- cancel()方法。- 有关线程安全性 and 子类化的说明,请参见 - add_timeout。- 版本 4.0 中新增。 
- IOLoop.call_later(delay: float, callback: Callable, *args: Any, **kwargs: Any) object[source]¶
- 在 - delay秒后运行- callback。- 返回一个不透明的句柄,可以传递给 - remove_timeout以取消。请注意,与- asyncio中同名方法不同,返回的对象没有- cancel()方法。- 有关线程安全性 and 子类化的说明,请参见 - add_timeout。- 版本 4.0 中新增。 
- IOLoop.remove_timeout(timeout: object) None[source]¶
- 取消挂起的超时。 - 参数是 - add_timeout返回的句柄。即使回调已经运行,调用- remove_timeout也是安全的。
- IOLoop.spawn_callback(callback: Callable, *args: Any, **kwargs: Any) None[source]¶
- 在下次 IOLoop 迭代时调用给定的回调。 - 从 Tornado 6.0 开始,此方法等效于 - add_callback。- 版本 4.0 中新增。 
- IOLoop.run_in_executor(executor: Optional[Executor], func: Callable[[...], _T], *args: Any) Future[_T][source]¶
- 在 - concurrent.futures.Executor中运行函数。如果- executor为- None,则将使用 IO 循环的默认执行器。- 使用 - functools.partial将关键字参数传递给- func。- 版本 5.0 中新增。 
- IOLoop.set_default_executor(executor: Executor) None[source]¶
- 设置用于 - run_in_executor()的默认执行器。- 版本 5.0 中新增。 
- IOLoop.time() float[source]¶
- 返回根据 - IOLoop的时钟获得的当前时间。- 返回值是一个相对于过去某个未指定时间的浮点数。 - 历史上,IOLoop 可以定制以使用例如 - time.monotonic而不是- time.time,但这目前不支持,因此此方法等效于- time.time。
- class tornado.ioloop.PeriodicCallback(callback: Callable[[], Optional[Awaitable]], callback_time: Union[timedelta, float], jitter: float = 0)[source]¶
- 定期调度给定回调函数。 - 当 - 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对象。- is_running() bool[source]¶
- 如果此 - PeriodicCallback已启动,则返回- True。- 版本 4.1 中的新功能。