Python Tornado - Confused how to convert a blocking function into a non-blocking function

笑着哭i 提交于 2019-12-18 21:53:43

问题


Suppose I have a long running function:

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

I have a get function in a handler that prints the user with the above result of a for loop that adds all the number in the xrange:

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

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

    print "end"

If I run the above code on two web browsers simultaneously, I get:

start

end

start

end

Which seems to be blocking. From my understanding, the @gen.coroutine and the yield statement does not block the IOLoop in the get function, however, if any functions that is inside the co-routine that is blocking, then it blocks the IOLoop.

Hence the other thing I did is to turn the long_running_function into a callback, and using the yield gen.Task instead.

@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)

This doesn't cut too, it gives me:

start

end

start

end

I can use threads to execute those in parallel, but it doesn't seem the way to go, because I might be opening a lot of threads, and according to Tornado's user guide, it may be expensive.

How do people write async libraries for Tornado?


回答1:


If the blocking function is CPU-bound (as your for/xrange example is), then threads (or processes) are the only way to make it non-blocking. Creating a thread per incoming request is expensive, but making a small ThreadPoolExecutor to handle all CPU-bound operations is not.

To make a function non-blocking without using threads, the function must be event-driven: it must be waiting on some external event (such as network I/O) so that it can be awoken when that event occurs.




回答2:


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:

  • Tornado blocking asynchronous requests - Answer by @koblas
  • Trying to call a long blocking function in tornado in a non blocking way

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



来源:https://stackoverflow.com/questions/32148713/python-tornado-confused-how-to-convert-a-blocking-function-into-a-non-blocking

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!