假設我們有兩個檔案,即mymanger.py和mysub.py。
mymanager.py
import time
from multiprocessing import Process
import mysub # the process file
def main():
xprocess = Process(
target=mysub.main,
)
xprocess.start()
xprocess.join()
time.sleep(1)
print(f"== Done, errorcode is {xprocess.exitcode} ==")
if __name__ == '__main__':
main()
mysub.py
import sys
def myexception(exc_type, exc_value, exc_traceback):
print("I want this to be printed!")
print("Uncaught exception", exc_type, exc_value, exc_traceback)
def main():
sys.excepthook = myexception # !!!
raise ValueError()
if __name__ == "__main__":
sys.exit()
執行mymanager.py結果輸出為:
Process Process-1:
Traceback (most recent call last):
File "c:\program files\python\3.9\lib\multiprocessing\process.py", line 315, in _bootstrap
self.run()
File "c:\program files\python\3.9\lib\multiprocessing\process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\lx\mysub.py", line 11, in main
raise ValueError()
ValueError
== Done, errorcode is 1 ==
當我期望的輸出是這樣的:
I want this to be printed!
Uncaught exception <class 'ValueError'> <traceback object at 0x0000027B6F952780>
如果我main在mysub.py沒有multiprocessing.Process.
我已經檢查了底層的 cpython (參考),問題似乎是函式中的try-exceptin_boostrap優先于我的子行程sys.excepthook,但據我了解,不應該先觸發子行程中的例外鉤子然后觸發exceptfrom _boostrap?
我需要子行程使用該sys.excepthook函式處理例外。我怎樣才能做到這一點?
uj5u.com熱心網友回復:
sys.excepthook當例外未被捕獲時被呼叫(一直冒泡出正在運行的程式)。但是Process物件在一個特殊的引導函式(BaseProcess._bootstrap如果它對你很重要)中運行它們的目標函式,該函式有意捕獲所有例外,列印有關失敗行程的資訊以及回溯,然后將退出代碼回傳給呼叫者(一個因啟動方法而異的啟動器)。
使用forkstart 方法時,呼叫者_bootstrapthen 退出作業os._exit(code)程式(“硬退出”命令繞過正常的例外處理系統,但由于您的例外已經被捕獲并處理,這幾乎無關緊要)。使用時'spawn',它使用普通sys.exitover os._exit,但 AFAICT 實作的SystemExit例外sys.exit在解釋器中是特殊情況,因此它sys.excepthook在未被捕獲時不會通過(大概是因為它通過例外實作被認為是實作細節;當你問退出程式與死于意外例外不同)。
總結:無論使用哪種 start 方法,都不可能讓您的代碼引發的例外“未處理”(為了達到的目的sys.excepthook),因為multiprocessing處理您的函式可以自行拋出的所有例外。如果包裝器代碼本身引發例外,理論上可以讓excepthook您在作業人員中設定執行以執行完成后引發的例外,但前提是您執行諸如替換 or 的定義之類的病態事情(并且它只會報告可怕的事情發生是因為您替換了它們,此時您自己的例外已經被吞沒了,所以不要那樣做)。targetmultiprocessingos._exitsys.exit
如果您真的想這樣做,最接近的方法是顯式捕獲例外并手動呼叫您的處理程式。例如,一個簡單的包裝函式將允許這樣做:
def handle_exceptions_with(excepthook, target, /, *args, **kwargs)
try:
target(*args, **kwargs)
except:
excepthook(*sys.exc_info())
raise # Or maybe convert to sys.exit(1) if you don't want multiprocessing to print it again
將您的Process啟動更改為:
xprocess = Process(
target=handle_exceptions_with,
args=(mysub.myexception, mysub.main)
)
或者一次性使用,只是懶惰,只重寫mysub.main為:
def main():
try:
raise ValueError()
except:
myexception(*sys.exc_info())
raise # Or maybe convert to sys.exit(1) if you don't want multiprocessing to print it again
并保持其他一切不變。您仍然可以將處理程式設定為sys.excepthook和/或threading.excepthook()(以處理在作業行程中啟動的執行緒可能因未處理的例外而死亡的情況),但它不適用于作業行程的主執行緒(或更準確地說,有沒有辦法讓例外到達它)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/473227.html
標籤:Python python-3.x 例外 多处理
