3

我有一个龙卷风应用程序,我想使用一个阻塞库来完成一些事情。在无法以异步方式重写库的情况下,在 tornado 中执行它的方法是什么?

例如,我希望能够@asynchronous在请求处理程序上放置一个装饰器,在它启动一些长时间运行的函数,一旦完成就会返回响应。我不能只是回调。最简单的例子当然是在不阻塞龙卷风唯一线程的情况下睡眠 10 秒的正确方法是什么?

4

3 回答 3

2

接受的答案所指的代码可在 SO 上找到

另一种方法在此处的博客文章中进行了详细介绍,并附有完整的工作要点。这是从要点重新发布的代码:

from concurrent.futures import ThreadPoolExecutor
from functools import partial, wraps
import time

import tornado.ioloop
import tornado.web


EXECUTOR = ThreadPoolExecutor(max_workers=4)


def unblock(f):

    @tornado.web.asynchronous
    @wraps(f)
    def wrapper(*args, **kwargs):
        self = args[0]

        def callback(future):
            self.write(future.result())
            self.finish()

        EXECUTOR.submit(
            partial(f, *args, **kwargs)
        ).add_done_callback(
            lambda future: tornado.ioloop.IOLoop.instance().add_callback(
                partial(callback, future)))

    return wrapper


class MainHandler(tornado.web.RequestHandler):

    def get(self):
        self.write("Hello, world %s" % time.time())


class SleepHandler(tornado.web.RequestHandler):

    @unblock
    def get(self, n):
        time.sleep(float(n))
        return "Awake! %s" % time.time()


class SleepAsyncHandler(tornado.web.RequestHandler):

    @tornado.web.asynchronous
    def get(self, n):

        def callback(future):
            self.write(future.result())
            self.finish()

        EXECUTOR.submit(
            partial(self.get_, n)
        ).add_done_callback(
            lambda future: tornado.ioloop.IOLoop.instance().add_callback(
                partial(callback, future)))

    def get_(self, n):
        time.sleep(float(n))
        return "Awake! %s" % time.time()


application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/sleep/(\d+)", SleepHandler),
    (r"/sleep_async/(\d+)", SleepAsyncHandler),
])


if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start() 
于 2015-03-05T03:32:47.920 回答
2

似乎我想要的只是创建一个新线程/进程,并且需要完成回调龙卷风的实际行为IOLoop.instance().add_callback

更多信息可在此处获得

于 2013-01-13T05:26:18.513 回答
1

试试下面这个例子。

import tornado.ioloop
import tornado.web
import time

class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self, request):
        if request is None:
            self.application.go = False
            self.write("Waiting for GET @ http://localhost:8888/go...<br>")
            self.flush()
            self._do_wait()
        else:
            self.application.go = True
            self.finish('Thanks!')

    def _do_wait(self, timeout_trys=10):
        if self.application.go:
            self.write('Finish')
            self.finish()
        else:
            self.write("Sleeping 2 second, timeout_trys=%s<br>" % timeout_trys)
            self.flush()
            tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 2, 
                lambda: self._do_wait(timeout_trys-1))


application = tornado.web.Application([
    (r"/(\w+)?", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
于 2013-01-12T22:18:42.427 回答