【问题标题】:How are errors handled within threads in Python?Python 线程中的错误是如何处理的?
【发布时间】:2020-01-15 03:18:30
【问题描述】:

我正在使用ThreadPoolExecutor 执行导致错误的函数。当一个线程中发生错误(并且它没有被处理)时,看起来它正在终止该线程,但没有向stderr 打印任何内容或导致程序崩溃。为什么会这样?我可以让任何线程中的未处理错误导致整个程序崩溃吗?或者它可以打印在某个地方,这样我就可以看到发生了什么。

我注意到错误可以在 try-catch 块中捕获,因此肯定会引发错误。如果在没有线程的情况下调用相同的函数,则会按预期引发错误。

from concurrent.futures import ThreadPoolExecutor
import time


def error_causer(x):
    print(x)
    raise ValueError("This bad!")


with ThreadPoolExecutor(max_workers=1) as executor:
    executor.map(error_causer, ["coming from thread"])

print("After don't catch. Should have crashed by now...")
time.sleep(2)

error_causer("coming from outside thread")

当在线程内引发 ValueError 时,该程序不会崩溃,但在线程外引发 ValueError 时会崩溃。

输出是:

coming from thread
After don't catch. Should have crashed by now...
coming from outside thread
Traceback (most recent call last):
  File "./another_threading_test.py", line 16, in <module>
    error_causer("coming from outside thread")
  File "./another_threading_test.py", line 7, in error_causer
    raise ValueError("This bad!")
ValueError: This bad!

我希望它在print("after don't catch") 之前崩溃

【问题讨论】:

    标签: python python-3.x multithreading error-handling python-multithreading


    【解决方案1】:

    executor.map() 不会引发错误,因为工作线程会静默终止而不会引发错误,除非您尝试从迭代器中检索结果,这是按照 docs

    map(func, *iterables, timeout=None, chunksize=1)

    如果 func 调用引发异常,则该异常将被引发 当它的值从迭代器中检索出来时。

    您可以通过在返回的iterator 上调用next() 来验证这一点:

    def error_causer(x):
        print(x)
        raise ValueError("This bad!")
    
    
    with ThreadPoolExecutor(max_workers=1) as executor:
        iterator = executor.map(error_causer, ["coming from thread"])
        next(iterator)
    

    现在在迭代器上调用next() 后,您会看到主线程中出现的错误来自终止主线程的工作线程:

    Traceback (most recent call last):
      File "/Users/ambhowmi/PycharmProjects/Datastructures/TwoStacksQueue.py", line 13, in <module>
        next(iterator)
      File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 598, in result_iterator
        yield fs.pop().result()
      File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 428, in result
        return self.__get_result()
      File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 384, in __get_result
        raise self._exception
      File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/thread.py", line 57, in run
        result = self.fn(*self.args, **self.kwargs)
      File "/Users/ambhowmi/PycharmProjects/Datastructures/TwoStacksQueue.py", line 8, in error_causer
        raise ValueError("This bad!")
    ValueError: This bad!
    

    【讨论】:

      猜你喜欢
      • 2017-02-11
      • 2017-02-07
      • 1970-01-01
      • 1970-01-01
      • 2021-03-15
      • 2014-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多