【问题标题】:Running blocking code in Tornado在 Tornado 中运行阻塞代码
【发布时间】:2013-01-12 12:19:28
【问题描述】:

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

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

【问题讨论】:

  • 您能否提供更多关于如何阻止龙卷风的信息?因为你总是可以做time.sleep(10),但我确定你想做其他事情......
  • @StevePeak 谢谢,我又加了一段
  • 有趣的是,我在我的一个应用程序中也有同样的概念。在此处查看我的 SO:stackoverflow.com/questions/13961863/… 您的问题与此有关吗?无论哪种方式,我都愿意帮助你。

标签: python asynchronous tornado


【解决方案1】:

看起来我想要的只是创建一个新线程/进程,而回调 tornado 的实际行为需要使用IOLoop.instance().add_callback 完成

更多信息请见here

【讨论】:

【解决方案2】:

接受的答案是指is available on SO的代码。

另一种方法在博文here 和a full working gist 中有详细介绍。这是从 gist 重新发布的代码:

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

【讨论】:

    【解决方案3】:

    试试下面这个例子。

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

    【讨论】:

    • 谢谢,但我认为我正在寻找的更像是我在此处的回答中显示的内容
    猜你喜欢
    • 1970-01-01
    • 2017-02-15
    • 1970-01-01
    • 2021-07-13
    • 2023-03-22
    • 2013-11-12
    • 1970-01-01
    • 2012-10-14
    • 2021-08-28
    相关资源
    最近更新 更多