【问题标题】:Python 3: Thread: Killing callable execution after Aborted due to Timeout?Python 3:线程:由于超时而中止后终止可调用执行?
【发布时间】:2016-11-27 08:40:44
【问题描述】:

线程的底层执行是否可以在由于超时而中止后被杀死?

我正在遵循此处提供的以下线程方法: Timeout a Python Callable

下面是此代码的 Python 3 修订版。

此代码通过在调用threading.Thread.abort() 时抛出RuntimeError 来正确超时可调用函数,这与将超时值分配给threading.Thread.join(timeout) 时的预期一致。

然而,即使线程被中止,底层的可调用对象仍在执行。

问题:如何在线程被中止后终止该线程以阻止底层可调用对象继续执行,而不终止父可执行文件?

这是我的代码:

import datetime as dt
import threading

def run_command_with_threaded_timeout(
    func,
    fargs=None,
    fkwargs=None,
    threaded_run_timeout_secs=None
):
    class TimedThread(threading.Thread):
        """An abortable thread, by raising an exception inside its
        context.
        """

        def __init__(self):
            super(TimedThread, self).__init__()
            self.exc_info = (None, None, None)

        def run(self):
            self.started_at = dt.datetime.now()
            try:
                args = fargs if fargs else list()
                kwargs = fkwargs if fkwargs else dict()
                request_func = partial(func, *args, **kwargs)
                self.result = request_func()
            except:
                # save the exception as an object attribute
                self.exc_info = sys.exc_info()
                self.result = None

            self.ended_at = dt.datetime.now()

        def abort(self):
            self.ended_at = dt.datetime.now()
            threaded_run_diff = self.ended_at - self.started_at
            threaded_run_diff_secs = threaded_run_diff.seconds                
            if threaded_run_diff_secs >= threaded_run_timeout_secs:
                raise RuntimeError(
                    "Threaded Run: Timed Out"
                    )

            raise RuntimeError(
                "Threaded Run: Aborted"
            )

    t = TimedThread()
    t.start()
    t.join(timeout=threaded_run_timeout_secs)
    if t.exc_info[0] is not None:  # if there were any exceptions
        exc_type, exc_value, exc_traceback = t.exc_info
        # Raise the exception/traceback inside the caller
        raise exc_type.with_traceback(exc_value, exc_traceback)

    if t.is_alive():
        t.abort()
        diff = t.ended_at - t.started_at            
        raise RuntimeError("%(f)s timed out after %(d)r seconds" %
                           {'f': func, 'd': diff.seconds})

    return t.result

【问题讨论】:

    标签: multithreading python-3.x timeout kill


    【解决方案1】:

    我读到的是一个线程不能从外部被杀死。

    可以做的是提供一个全局变量,由线程读取以确定它是否还活着。

    global is_alive = True
    kwargs = {
        'config_job': config_job,
        'config_request_params': config_request_params,
        'config_request_credentials': config_request_credentials,
        'config_request_retry': config_request_retry
    }
    
    try:
        response = run_command_with_threaded_timeout(
            func=cmd,
            fargs=None,
            fkwargs=kwargs,
            timeout_sec=timeout_sec
        )
    except Exception as ex:
        is_alive = False
        raise
    

    【讨论】:

    • 尽管这已经相当老了,但它在搜索中不断弹出。通常应避免使用“全局”。特别是对于在线程(和进程)之间传递信息。考虑改用事件
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 2013-04-20
    • 2018-03-03
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多