我怎样才能取消挂asyncronous任务龙卷风,一个超时? [英] How can I cancel a hanging asyncronous task in tornado, with a timeout?

查看:301
本文介绍了我怎样才能取消挂asyncronous任务龙卷风,一个超时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的设置是蟒蛇龙卷风服务器,该服务器异步处理与的ThreadPoolExecutor 任务。在某些情况下,任务可能变成无限循环。随着 with_timeout 装饰,我已成功地捕捉到超时异常和错误的结果返回给客户端。问题是,该任务仍然在后台运行。它是如何可能从运行中停止任务的的ThreadPoolExecutor ?或者是有可能取消未来
这里是code能重现问题。运行code。与龙卷风4和concurrent.futures库和去的http://本地主机:8888 /测试

 从tornado.concurrent进口run_on_executor
从tornado.gen进口with_timeout
从tornado.ioloop进口IOLoop
进口tornado.web
从龙卷风进口根
从concurrent.futures进口的ThreadPoolExecutor
进口日期时间
MAX_WAIT_SECONDS = 10类MainHandler(tornado.web.RequestHandler):
    遗嘱执行人=的ThreadPoolExecutor(2)    @run_on_executor
    高清test_func(个体经营):
        ...
        #infinite循环可能会在这里
        ...    @ tornado.gen.coroutine
    DEF得到(个体经营):
        未来= self.test_func()
        尝试:
            result_search_struct =产量with_timeout(datetime.timedelta(秒= MAX_WAIT_SECONDS),未来)
            self.write({'状态':0})
            self.finish()
        除例外,E:
            #如何在这里取消任务,如果它是超时
            future.cancel()#< - 不工作
            self.write({状态:100})
            self.finish()应用= tornado.web.Application([
    (R/测试,MainHandler)
])
application.listen(8888)
IOLoop.instance()。开始()


解决方案
一旦他们实际执行

未来实例本身不能被取消,他们只能被取消如果他们处于挂起状态。这说明在文档


  

取消()


  
  

尝试取消呼叫。如果当前正在执行的呼叫,无法取消,则该方法将返回
  否则通话将被取消,该方法将返回


所以,放弃你在后台运行的方法,唯一的办法就是实际的逻辑插入到你的潜在的无限循环,以便它可以当你告诉它被中止。随着你的榜样,你可以使用 threading.Event

 类MainHandler(tornado.web.RequestHandler):
    遗嘱执行人=的ThreadPoolExecutor(2)    @run_on_executor
    高清test_func(个体经营,事件):
        I = 0
        同时不event.is_set():
            我打印
            I = I + 1    @ tornado.gen.coroutine
    DEF得到(个体经营):
        事件= threading.Event()
        未来= self.test_func(事件)
        尝试:
            result_search_struct =产量with_timeout(datetime.timedelta(秒= MAX_WAIT_SECONDS),未来)
            self.write({'状态':0})
            self.finish()
        除例外,E:
            future.cancel()#可能不起作用,这取决于执行者的繁忙程度
            event.set()
            self.write({状态:100})
            self.finish()应用= tornado.web.Application([
    (R/测试,MainHandler)
])

My setup is python tornado server, which asynchronously processes tasks with a ThreadPoolExecutor. In some conditions, the task might turn into infinite loop. With the with_timeout decorator, I have managed to catch the timeout exception and return an error result to the client. The problem is that the task is still running in the background. How it is possible to stop the task from running in the ThreadPoolExecutor? Or is it possible to cancel the Future? Here is the code that reproduces the problem. Run the code with tornado 4 and concurrent.futures libraries and go to http://localhost:8888/test

from tornado.concurrent import run_on_executor
from tornado.gen import with_timeout
from tornado.ioloop import IOLoop
import tornado.web
from tornado import gen
from concurrent.futures import ThreadPoolExecutor
import datetime
MAX_WAIT_SECONDS = 10

class MainHandler(tornado.web.RequestHandler):
    executor = ThreadPoolExecutor(2)

    @run_on_executor
    def test_func(self):
        ...
        #infinite loop might be here
        ...

    @tornado.gen.coroutine
    def get(self):
        future = self.test_func()
        try:
            result_search_struct = yield with_timeout(datetime.timedelta(seconds=MAX_WAIT_SECONDS), future )
            self.write({'status' : 0})
            self.finish()
        except Exception, e:
            #how to cancel the task here if it was timeout
            future.cancel() # <-- Does not work
            self.write({'status' : 100})
            self.finish()

application = tornado.web.Application([
    (r"/test", MainHandler),
])
application.listen(8888)
IOLoop.instance().start()

解决方案

Future instances themselves can't be cancelled once they're actually executing, they can only be cancelled if they're in a pending state. This is noted in the docs:

cancel()

Attempt to cancel the call. If the call is currently being executed and cannot be cancelled then the method will return False, otherwise the call will be cancelled and the method will return True.

So, the only way to abort the method you're running in the background is to actually insert logic into your potentially infinite loop so that it can be aborted when you tell it to. With your example, you could use a threading.Event:

class MainHandler(tornado.web.RequestHandler):
    executor = ThreadPoolExecutor(2)

    @run_on_executor
    def test_func(self, event):
        i = 0
        while not event.is_set():
            print i
            i = i + 1

    @tornado.gen.coroutine
    def get(self):
        event = threading.Event()
        future = self.test_func(event)
        try:
            result_search_struct = yield with_timeout(datetime.timedelta(seconds=MAX_WAIT_SECONDS), future )
            self.write({'status' : 0})
            self.finish()
        except Exception, e:
            future.cancel() # Might not work, depending on how busy the Executor is
            event.set()
            self.write({'status' : 100})
            self.finish()

application = tornado.web.Application([
    (r"/test", MainHandler),
])

这篇关于我怎样才能取消挂asyncronous任务龙卷风,一个超时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆