首页 > 解决方案 > 如何在不指定超时值的情况下处理失败的守护线程并继续主线程?

问题描述

我有两个同时运行的函数作为守护线程,它们都将它们的输出放到队列中,一旦较快的一个完成,主线程就会继续 - 较慢的一个要么有价值,要么失败,没关系。我们不知道哪个会先完成,但我的目标是始终以更快的结果返回主线程,如果两个线程中都没有引发异常,这与以下代码配合得很好。我的问题是处理两者都失败的情况,在这种情况下,我想立即返回主线程。

def search1(Q_result, name):
    raise Exception("search1 raised an exception, not putting any output to the queue...")
    result = somefunction()
    Q_result.put(result)

def search2(Q_result, name):
    raise Exception("search2 raised an exception, not putting any output to the queue...")
    result = somefunction()
    Q_result.put(result )


import Queue as queue
import threading

Q_result = queue.Queue()  # create a Queue to hold the result(s)

if __name__=='__main__':

    t1 = threading.Thread(
        target=search1,
        args=(Q_result, name),
    )
    t1.daemon = True
    t1.start()
        

    t2 = threading.Thread(
        target=search2,
        args=(Q_result),
    )
    t2.daemon = True
    t2.start()


try:
    res = Q_result.get(timeout=10)
    print res
except queue.Empty:
    print "Queue is empty, returning to main thread..."

timeout=10 秒后的输出:

search1 raised an exception, not putting any output to the queue...
search2 raised an exception, not putting any output to the queue...
Queue is empty, returning to main thread...

这种方法有两个问题:

如何处理?(@ti7 @ Arty 有什么建议吗?)

标签: multithreadingpython-2.7

解决方案


您需要在两个工作人员的函数中捕获异常(try/catch),并将一些特殊的值标记None或字符串等"__BAD_VALUE__"放入队列中。

然后 main 检查队列中的第一个结果是否不等于该标记 ( None) 然后第一个好的结果准备好并且 main 应该打印或将其返回给用户。如果队列中的第一个结果看起来很糟糕(None),那么 main 应该等待队列中的第二个结果。如果 second 还不错(不是None),则将其返回给用户,否则 worker 失败和 main 都应该报告完全失败,或者可能以某种方式重做两个 API 调用的整个过程。

在队列获取函数中仍然需要超时,因为任何工作人员都可以出于某种原因无限期挂起而没有任何例外,如果两个工作人员都被挂起,那么 main 应该退出并再次报告完全失败,但原因是挂起工作人员(不例外)。

完整代码如下:

在线尝试!

import time
name = 'abc'

def search1(Q_result, name):
    try:
        raise Exception("search1 raised an exception, not putting any output to the queue...")
        #result = somefunction()
        result = 'first_result'
        Q_result.put(result)
    except:
        Q_result.put(None)

def search2(Q_result, name):
    try:
        time.sleep(1)
        #raise Exception("search2 raised an exception, not putting any output to the queue...")
        #result = somefunction()
        result = 'second_result'
        Q_result.put(result )
    except:
        Q_result.put(None)


import Queue as queue
import threading

Q_result = queue.Queue()  # create a Queue to hold the result(s)

if __name__=='__main__':

    t1 = threading.Thread(
        target=search1,
        args=(Q_result, name),
    )
    t1.daemon = True
    t1.start()
        

    t2 = threading.Thread(
        target=search2,
        args=(Q_result, name),
    )
    t2.daemon = True
    t2.start()


try:
    res = Q_result.get(timeout = 10)
    if res is None:
        res = Q_result.get(timeout = 10)
        if res is None:
            print('Both funcs had exceptions/errors, total failure, do something!')
    if res is not None:
        print(res)
except queue.Empty:
    print('Function has frozen for too long, total failure, do something!')

推荐阅读