Python Tornado - 困惑如何将阻塞函数转换为非阻塞函数

标签 python tornado

假设我有一个长时间运行的函数:

def long_running_function():
    result_future = Future()
    result = 0
    for i in xrange(500000):
        result += i
    result_future.set_result(result)
    return result_future

我在处理程序中有一个 get 函数,它向用户打印上述 for 循环的结果,该循环将 xrange 中的所有数字相加:

@gen.coroutine
def get(self):
    print "start"

    self.future = long_running_function()
    message = yield self.future
    self.write(str(message))

    print "end"

如果我同时在两个网络浏览器上运行上面的代码,我会得到:

开始

结束

开始

结束

这似乎是阻塞的。据我了解,@gen.coroutineyield 语句不会阻止 get 函数中的 IOLoop,但是,如果协程中的任何函数阻塞,然后它阻塞 IOLoop。

因此,我做的另一件事是将 long_running_function 转换为回调,并改用 yield gen.Task

@gen.coroutine
def get(self):
    print "start"

    self.future = self.long_running_function
    message = yield gen.Task(self.future, None)
    self.write(str(message))

    print "end"

def long_running_function(self, arguments, callback):
    result = 0
    for i in xrange(50000000):
        result += i
    return callback(result)

这并没有削减太多,它给了我:

开始

结束

开始

结束

我可以使用线程来并行执行它们,但这似乎不是可行的方法,因为我可能会打开很多线程,而且根据 Tornado 的用户指南,它可能很昂贵。

人们如何为 Tornado 编写异步库?

最佳答案

如果阻塞函数受 CPU 限制(如您的 for/xrange 示例),那么线程(或进程)是使其成为非阻塞的唯一方法。为每个传入请求创建一个线程是昂贵的,但制作一个小型 ThreadPoolExecutor 来处理所有 CPU 绑定(bind)操作则不是。

要使一个函数在不使用线程的情况下成为非阻塞的,该函数必须是事件驱动的:它必须等待一些外部事件(例如网络 I/O)以便它可以当该事件发生时被唤醒。

关于Python Tornado - 困惑如何将阻塞函数转换为非阻塞函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32148713/

相关文章:

python - 如何在 AI 平台培训中将 pandas-gbq 与 BigQuery Storage API 结合使用?

python - 在常规 python 脚本中使用 Tornado 异步代码

python - 如何在本地运行 Tornado Web 服务器?

python - 编写一个同样产生正常值的 Tornado 协程

python - 如何在 python 3 中为 OrderedDict 实现插入

python - 使用 Python 打印到 CSV 文件

python - Tornado Websockets 在没有 ping 的情况下不会调用 on_message

python + Tornado : 404 on imported request handler

python - 在 Django shell 启动时自动导入模型

python - 我可以手动 ssh,但不能通过脚本 - 权限被拒绝(公钥)