[英]Using nested asyncio.gather() inside another asyncio.gather()
[英]Inner exception is not being raised using asyncio.gather
使用Python 3.7,我嘗試按照在StackOverflow上找到的示例捕獲異常並重新引發它。 盡管該示例確實有效,但似乎並非在所有情況下都適用。 下面,我有兩個異步Python腳本,它們試圖重新引發異常。 第一個示例有效,它將同時打印內部和外部異常。
import asyncio
class Foo:
async def throw_exception(self):
raise Exception("This is the inner exception")
async def do_the_thing(self):
try:
await self.throw_exception()
except Exception as e:
raise Exception("This is the outer exception") from e
async def run():
await Foo().do_the_thing()
def main():
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
if __name__ == "__main__":
main()
運行此命令將正確輸出以下異常堆棧跟蹤:
$ py test.py
Traceback (most recent call last):
File "test.py", line 9, in do_the_thing
await self.throw_exception()
File "test.py", line 5, in throw_exception
raise Exception("This is the inner exception")
Exception: This is the inner exception
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "test.py", line 21, in <module>
main()
File "test.py", line 18, in main
loop.run_until_complete(run())
File "C:\Python37\lib\asyncio\base_events.py", line 584, in run_until_complete
return future.result()
File "test.py", line 14, in run
await Foo().do_the_thing()
File "test.py", line 11, in do_the_thing
raise Exception("This is the outer exception") from e
Exception: This is the outer exception
但是,在我的下一個Python腳本中,我有多個任務要排隊,我想從中獲得類似的異常堆棧跟蹤。 本質上,除了上述堆棧跟蹤,我將被打印3次(以下腳本中的每個任務一次)。 上面和下面的腳本之間的唯一區別是run()
函數。
import asyncio
class Foo:
async def throw_exception(self):
raise Exception("This is the inner exception")
async def do_the_thing(self):
try:
await self.throw_exception()
except Exception as e:
raise Exception("This is the outer exception") from e
async def run():
tasks = []
foo = Foo()
tasks.append(asyncio.create_task(foo.do_the_thing()))
tasks.append(asyncio.create_task(foo.do_the_thing()))
tasks.append(asyncio.create_task(foo.do_the_thing()))
results = await asyncio.gather(*tasks, return_exceptions=True)
for result in results:
if isinstance(result, Exception):
print(f"Unexpected exception: {result}")
def main():
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
if __name__ == "__main__":
main()
上面的代碼片段產生了令人失望的簡短異常,缺少堆棧跟蹤。
$ py test.py
Unexpected exception: This is the outer exception
Unexpected exception: This is the outer exception
Unexpected exception: This is the outer exception
如果將return_exceptions
更改為False
,則將獲得異常和堆棧跟蹤打印一次,然后停止執行,並取消其余兩個任務。 輸出與第一個腳本的輸出相同。 這種方法的缺點是,即使遇到異常,我也要繼續處理任務,然后在所有任務完成時在最后顯示所有異常。
如果不提供return_exceptions=True
參數,則asyncio.gather
將在第一個異常處停止,因此您的方法是正確的:您需要首先收集所有結果和異常,然后顯示它們。
為了獲得您所缺少的完整堆棧跟蹤,您將需要做的不僅僅是“打印”異常。 看一下stdlib中的traceback
模塊,該模塊具有您所需的全部功能: https : //docs.python.org/3/library/traceback.html
您也可以使用logging.exception
,或多或少地做同樣的事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.