2015-08-21 21 views
7

假设我有一个长期运行的功能:Python的龙卷风 - 困惑如何阻塞函数转换成一个无阻塞功能

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语句不阻止IOLoop在get函数,但是,如果这是阻断协程内的任何功能,那么它会阻止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) 

这不切得,它给了我:

开始

开始

我可以使用线程来执行那些平行,但它似乎并没有要走的路,因为我可能会开了很多THRE广告,并根据龙卷风的用户指南,它可能是昂贵的。

人们如何写龙卷风异步库?

回答

6

如果阻塞函数是CPU绑定的(就像你的for/xrange例子那样),那么线程(或者进程)是使它无阻塞的唯一方法。创建每个传入请求的线程是昂贵的,但做一个小的ThreadPoolExecutor来处理所有CPU绑定操作是没有的。

为了使功能无阻塞,而无需使用螺纹,该函数必须是事件驱动:它必须等待某些外部事件(例如,网络I/O),以便它可以被唤醒时该事件发生。

+0

我认为你是对的,但是[Calling-blocking-functions](htt p://www.tornadoweb.org/en/stable/guide/coroutines.html#calling-blocking-functions)没有提到CPU绑定或事件驱动,它只是说:“最简单的方法来调用来自协同程序的阻塞函数是使用ThreadPoolExecutor,它返回与协程兼容的Futures“ –

0

我目前正在努力增加一个网络接口,使用龙卷风和WebSocket的功能,我的模拟程序。 我的仿真程序是计算密集型的,即由@ ben-darnell说的CPU限制任务,应该使用另一个线程进程来实现。

多次调查之后,我觉得这些资源可能会有所帮助:

我现在在做类似的实现,并且会更新这个答案时,我有更多的进展:)