tornado.ioloop — 主事件循环

用于非阻塞套接字的 I/O 事件循环。

在 Tornado 6.0 中,IOLoopasyncio 事件循环的包装器,具有略微不同的接口。 IOLoop 接口现在主要用于向后兼容性;新代码通常应该直接使用 asyncio 事件循环接口。 IOLoop.current 类方法提供了对应于正在运行的 asyncio 事件循环的 IOLoop 实例。

IOLoop 对象

class tornado.ioloop.IOLoop(*args: Any, **kwargs: Any)[source]

一个 I/O 事件循环。

从 Tornado 6.0 开始,IOLoopasyncio 事件循环的包装器。

简单 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.processmultiprocessing 模块)应该尽早执行,理想情况下是应用程序在加载其配置后执行的第一件事,并且在任何调用 IOLoop.startasyncio.run 之前执行。

在版本 4.2 中变更: IOLoop 构造函数中添加了 make_current 关键字参数。

在版本 5.0 中变更: 默认情况下使用 asyncio 事件循环。 IOLoop.configure 方法不能在 Python 3 上使用,除非是冗余地指定 asyncio 事件循环。

在版本 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 会很有用,这样启动时运行的代码就可以找到正确的实例。

版本 4.1 中变更: 当没有当前 IOLoop 时创建的 IOLoop 会自动成为当前循环。

版本 5.0 中变更: 此方法还会设置当前的 asyncio 事件循环。

版本 6.2 起弃用: 通过 Tornado 设置和清除当前事件循环已弃用。如果您需要此功能,请改用 asyncio.set_event_loop

static IOLoop.clear_current() None[source]

清除当前线程的 IOLoop

主要供测试框架在测试之间使用。

版本 5.0 中变更: 此方法还会清除当前的 asyncio 事件循环。

版本 6.2 起弃用。

IOLoop.start() None[source]

启动 I/O 循环。

循环将一直运行,直到某个回调调用 stop(),这将使循环在当前事件迭代完成后停止。

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,该 IOLoopIOLoop.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.READIOLoop.WRITEIOLoop.ERROR 的按位或。

当事件发生时,将运行 handler(fd, events)

在版本 4.0 中变更: 添加了除了原始文件描述符之外还可以传递文件类对象的功能。

IOLoop.update_handler(fd: Union[int, _Selectable], events: int) None[source]

更改我们对 fd 监听的事件。

在版本 4.0 中变更: 添加了除了原始文件描述符之外还可以传递文件类对象的功能。

IOLoop.remove_handler(fd: Union[int, _Selectable]) None[source]

停止监听 fd 上的事件。

在版本 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_timeoutcall_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 中运行函数。如果 executorNone,则将使用 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 对象。

start() None[source]

启动计时器。

stop() None[source]

停止计时器。

is_running() bool[source]

如果此 PeriodicCallback 已启动,则返回 True

版本 4.1 中的新功能。