Skip to main content

tornado.ioloop —主事件循环

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

典型的应用程序将使用单个 IOLoop 对象,在 IOLoop.instance 单例中。通常在 main() 函数结束时调用 IOLoop.start 方法。非典型应用可以使用多于一个 IOLoop,例如每个线程一个 IOLoop,或每个 unittest 情况。

除了I/O事件,IOLoop 还可以安排基于时间的事件。 IOLoop.add_timeouttime.sleep 的非阻塞性替代。

IOLoop对象

class tornado.ioloop.IOLoop[源代码]

电平触发I/O回路。

我们使用 epoll (Linux)或 kqueue (BSD和Mac OS X),如果他们可用,否则我们回到select()。如果要实现需要处理数千个并发连接的系统,则应使用支持 epollkqueue 的系统。

简单TCP服务器的用法示例:

import errno
import functools
import tornado.ioloop
import socket

def connection_ready(sock, fd, events):
    while True:
        try:
            connection, address = sock.accept()
        except socket.error as e:
            if e.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
                raise
            return
        connection.setblocking(0)
        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(("", port))
    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 将不会尝试变为当前。

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

运行IOLoop

static IOLoop.current(instance=True)[源代码]

返回当前线程的 IOLoop

如果 IOLoop 当前正在运行或已被 make_current 标记为当前,则返回该实例。如果没有当前 IOLoop,如果 instance 为真,则返回 IOLoop.instance() (即主线程的 IOLoop,如果必要则创建一个 IOLoop)。

一般来说,你应该使用 IOLoop.current 作为默认情况下构造异步对象,并使用 IOLoop.instance,当你的意思是从一个不同的主线程通信。

在 4.1 版更改: 添加了 instance 参数以控制回退到 IOLoop.instance()

IOLoop.make_current()[源代码]

使这个 IOLoop 为当前线程。

IOLoop 在启动时自动变为当前线程,但有时在启动 IOLoop 之前显式调用 make_current 有时很有用,因此在启动时运行的代码可以找到正确的实例。

在 4.1 版更改: 在没有当前 IOLoop 时创建的 IOLoop 将自动变为当前。

static IOLoop.instance()[源代码]

返回全局 IOLoop 实例。

大多数应用程序具有在主线程上运行的单个全局 IOLoop。使用此方法从另一个线程获取此实例。在大多数其他情况下,最好使用 current() 来获取当前线程的 IOLoop

static IOLoop.initialized()[源代码]

如果已创建单例实例,则返回true。

IOLoop.install()[源代码]

将此 IOLoop 对象作为单例实例安装。

这通常不是必需的,因为 instance() 将根据需要创建 IOLoop,但是您可能想要调用 install 来使用 IOLoop 的自定义子类。

当使用 IOLoop 子类时,必须在创建任何隐式创建自己的 IOLoop (例如 tornado.httpclient.AsyncHTTPClient)的对象之前调用 install

static IOLoop.clear_instance()[源代码]

清除全局 IOLoop 实例。

4.0 新版功能.

IOLoop.start()[源代码]

启动I/O循环。

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

IOLoop.stop()[源代码]

停止I/O循环。

如果事件循环当前未运行,则下一次调用 start() 将立即返回。

要使用异步方法从同步代码(如单元测试),你可以像这样启动和停止事件循环:

ioloop = IOLoop()
async_method(ioloop=ioloop, callback=ioloop.stop)
ioloop.start()

ioloop.start() 将在 async_method 运行其回调之后返回,无论该回调是在 ioloop.start 之前还是之后调用。

注意,即使在 stop 被调用之后,IOLoop 也不会完全停止,直到 IOLoop.start 也返回。在调用 stop 之前安排的一些工作可能仍然在 IOLoop 关闭之前运行。

IOLoop.run_sync(func, timeout=None)[源代码]

启动 IOLoop,运行给定的函数,并停止循环。

该函数必须返回一个yieldable对象或 None。如果函数返回一个yieldable对象,IOLoop 将运行,直到yieldable解决(和 run_sync() 将返回yieldable的结果)。如果引发异常,IOLoop 将停止,异常将重新提交给调用者。

仅关键字参数 timeout 可用于设置函数的最大持续时间。如果超时到期,则产生 TimeoutError

此方法与 tornado.gen.coroutine 结合使用,可在 main() 函数中允许异步调用:

@gen.coroutine
def main():
    # do stuff...

if __name__ == '__main__':
    IOLoop.current().run_sync(main)

在 4.3 版更改: 返回非 None,不可屈服值现在是错误。

IOLoop.close(all_fds=False)[源代码]

关闭 IOLoop,释放所使用的任何资源。

如果 all_fds 为真,则在IOLoop上注册的所有文件描述符都将被关闭(不仅仅是由 IOLoop 本身创建的)。

许多应用程序将只使用在进程的整个生命周期运行的单个 IOLoop。在这种情况下,关闭 IOLoop 不是必需的,因为当进程退出时将清除所有内容。 IOLoop.close 主要用于创建和销毁大量 IOLoops 的单元测试等场景。

IOLoop 必须完全停止才能关闭。这意味着 IOLoop.stop() 必须被调用 and IOLoop.start() 必须允许在尝试调用 IOLoop.close() 之前返回。因此,对 close 的呼叫通常将在呼叫 start 之后出现,而不是接近对 stop 的呼叫。

在 3.1 版更改: 如果 IOLoop 实现支持“文件描述符”的非整数对象,那么当 all_fds 为真时,那些对象将具有其 close 方法。

I/O事件

IOLoop.add_handler(fd, handler, events)[源代码]

注册给定的处理程序以接收 fd 的给定事件。

fd 参数可以是整数文件描述符或具有 fileno() 方法的文件状对象(以及可选地 close() 方法,其可以在 IOLoop 被关闭时被调用)。

events 参数是按位或常量 IOLoop.READIOLoop.WRITEIOLoop.ERROR

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

在 4.0 版更改: 添加了除原始文件描述符之外传递文件类对象的能力。

IOLoop.update_handler(fd, events)[源代码]

更改我们侦听 fd 的事件。

在 4.0 版更改: 添加了除原始文件描述符之外传递文件类对象的能力。

IOLoop.remove_handler(fd)[源代码]

停止侦听 fd 上的事件。

在 4.0 版更改: 添加了除原始文件描述符之外传递文件类对象的能力。

回调和超时

IOLoop.add_callback(callback, *args, **kwargs)[源代码]

在下一个I/O循环迭代中调用给定的回调。

从任何线程调用此方法是安全的,除了从信号处理程序。注意,这是 IOLoop 中的 只要 方法,其使得该线程安全性保证;所有与 IOLoop 的其他交互必须从 IOLoop 的线程完成。 add_callback() 可用于将控制从其他线程传输到 IOLoop 的线程。

要从信号处理程序添加回调,请参阅 add_callback_from_signal

IOLoop.add_callback_from_signal(callback, *args, **kwargs)[源代码]

在下一个I/O循环迭代中调用给定的回调。

安全使用从Python信号处理程序;不应该使用。

使用此方法添加的回调将在没有任何 stack_context 的情况下运行,以避免拾取被信号中断的函数的上下文。

IOLoop.add_future(future, callback)[源代码]

当给定的 Future 完成时,调度 IOLoop 上的回调。

回调使用一个参数 Future 来调用。

IOLoop.add_timeout(deadline, callback, *args, **kwargs)[源代码]

在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 通常更容易实现,但希望保持与4.0之前的Tornado版本兼容性的子类必须使用 add_timeout

在 4.0 版更改: 现在通过 *args**kwargs 到回调。

IOLoop.call_at(when, callback, *args, **kwargs)[源代码]

when 指定的绝对时间运行 callback

when 必须是使用与 IOLoop.time 相同参考点的数字。

返回可以被传递到 remove_timeout 取消的不透明句柄。注意,与同名的 asyncio 方法不同,返回的对象没有 cancel() 方法。

有关线程安全和子类化的评论,请参阅 add_timeout

4.0 新版功能.

IOLoop.call_later(delay, callback, *args, **kwargs)[源代码]

delay 秒过后运行 callback

返回可以被传递到 remove_timeout 取消的不透明句柄。注意,与同名的 asyncio 方法不同,返回的对象没有 cancel() 方法。

有关线程安全和子类化的评论,请参阅 add_timeout

4.0 新版功能.

IOLoop.remove_timeout(timeout)[源代码]

取消待处理的超时。

参数是 add_timeout 返回的句柄。即使回调已经运行,也可以调用 remove_timeout

IOLoop.spawn_callback(callback, *args, **kwargs)[源代码]

在下一个IOLoop迭代上调用给定的回调。

与IOLoop上的所有其他回调相关的方法不同,spawn_callback 不将回调与其调用者的 stack_context 关联,因此它适用于不应干扰调用者的fire-and-forget回调。

4.0 新版功能.

IOLoop.time()[源代码]

根据 IOLoop 的时钟返回当前时间。

返回值是相对于过去的未指定时间的浮点数。

默认情况下,IOLoop 的时间函数为 time.time。然而,它可以被配置成使用例如 time.monotonic。对 add_timeout 传递一个数字而不是 datetime.timedelta 的调用应使用此函数计算适当的时间,因此无论选择什么时间函数,它们都可以工作。

class tornado.ioloop.PeriodicCallback(callback, callback_time, io_loop=None)[源代码]

调度要定期调用的给定回调。

每个 callback_time 毫秒都调用回调。请注意,超时以毫秒为单位,而Tornado中的大多数其他与时间相关的函数使用秒。

如果回调运行的时间长于 callback_time 毫秒,则将跳过后续调用以按计划返回。

在创建 PeriodicCallback 之后必须调用 start

在 4.1 版更改: io_loop 参数已弃用。

start()[源代码]

启动定时器。

stop()[源代码]

停止定时器。

is_running()[源代码]

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

4.1 新版功能.

调试和错误处理

IOLoop.handle_callback_exception(callback)[源代码]

每当 IOLoop 运行的回调抛出异常时,将调用此方法。

默认情况下,只是将异常记录为错误。子类可以覆盖此方法以自定义异常报告。

异常本身未明确传递,但在 sys.exc_info 中可用。

IOLoop.set_blocking_signal_threshold(seconds, action)[源代码]

如果 IOLoop 被阻塞超过 s 秒,则发送信号。

通过 seconds=None 禁用。在unixy平台上需要Python 2.6。

action参数是一个Python信号处理程序。有关详细信息,请阅读 signal 模块的文档。如果 action 为None,如果阻塞时间过长,进程将被终止。

IOLoop.set_blocking_log_threshold(seconds)[源代码]

如果 IOLoop 被阻止超过 s 秒,则记录堆栈跟踪。

相当于 set_blocking_signal_threshold(seconds, self.log_stack)

IOLoop.log_stack(signal, frame)[源代码]

信号处理程序记录当前线程的堆栈跟踪。

用于 set_blocking_signal_threshold

子类的方法

IOLoop.initialize(make_current=None)[源代码]
IOLoop.close_fd(fd)[源代码]

关闭 fd 的实用方法。

如果 fd 是一个类文件对象,我们直接关闭它;否则我们使用 os.close

此方法提供给 IOLoop 子类使用(在 IOLoop.close(all_fds=True) 的实现中,通常不应用于应用程序代码。

4.0 新版功能.

IOLoop.split_fd(fd)[源代码]

fd 参数返回(fd,obj)对。

我们接受原始文件描述符和类文件对象作为 add_handler 和相关方法的输入。当一个类文件对象被传递,我们必须保留对象本身,所以我们可以在 IOLoop 关闭时正确关闭它,但是poller接口支持文件描述符(他们将接受文件类对象并为你调用 fileno(),但是他们总是返回描述符本身)。

此方法提供供 IOLoop 子类使用,通常不应由应用程序代码使用。

4.0 新版功能.