Python Tornado - 混淆了如何将阻塞函数转换为非阻塞函数

时间:2015-08-21 20:21:55

标签: 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编写异步库?

2 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:0)

I'm currently struggling to add a web interface for my simulation program using Tornado and its WebSocket function. My simulation program is computationally intensive, i.e., CPU-bound task as said by @ben-darnell , which should be implemented using another thread or process.

After many investigations, I think these resources may be helpful:

I'm doing the similar implementation now, and will update this answer when I have more progress :)