如何处理失败的守护线程并在不指定超时值的情况下继续主线程? [英] How to handle failing daemon threads and continue the main thread without specifying a timeout value?

查看:62
本文介绍了如何处理失败的守护线程并在不指定超时值的情况下继续主线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have two simultaneously running functions as daemon threads, both putting their output to the queue and once the faster one completes, the main thread continues - the slower one either has value or fails, it doesn't matter. We do not know which one will be completed first, but my goal is to always return the main thread with the quicker one's result, which works well with the following code if no exception is raised in either thread. My problem is handling the case when both fail, in that case, I want to instantly return to the main thread.

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..."

超时=10秒后的输出:

The output after the timeout=10 seconds:

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...

这种方法有两个问题:

  • 如果两个线程失败的时间比超时时间短怎么办,例如在 2 秒内 - 然后我等待 8 秒返回主线程,而不是在 2 秒内返回
  • 如果其中一个搜索线程花费的时间比超时时间长(我对此没有太多控制权来处理)并且会返回一个有效的输出,但超时会在线程返回之前杀死该线程.

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

How to handle this? (@ti7, @Arty any suggestion?)

推荐答案

您需要在两个 worker 函数中捕获异常(try/catch),并放置一些特殊的值标记,例如 None 或一些像 "__BAD_VALUE__" 这样的字符串进入队列.

You need to catch exceptions (try/catch) in both workers' functions and put some special value-marker like None or some string like "__BAD_VALUE__" into the queue.

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

Then main checks if first result in queue is not equal to this marker (None) then first good result is ready and main should print or return it to user. If first result in queue appeared to be bad (None) then main should wait for second result in queue. If second is not bad (not None) then it is returned to user, otherwise both workers failed and main should report total failure or somehow maybe redo whole process of two API calls.

在 queue get 函数中仍然需要超时,因为任何工人都可以出于某种原因无限期地挂起而没有任何例外,如果两个工人都挂了,那么 main 应该退出并再次报告完全失败,但由于工人挂起的原因(不排除).

Also timeout is still needed inside queue get function because any worker can hang for indefinite time for some reason without any exceptions and if both workers hanged then main should quit and report total failure again but for the reason of hanging workers (not excepting).

完整代码如下:

在线试玩

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!')

这篇关于如何处理失败的守护线程并在不指定超时值的情况下继续主线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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