gpt4 book ai didi

python-3.x - 调试异步函数时如何检索原始调用堆栈?

转载 作者:行者123 更新时间:2023-12-04 20:36:04 24 4
gpt4 key购买 nike

鉴于此示例代码

#!/usr/bin/python3
import asyncio

async def f1():
await f2()
async def f2():
try:
await asyncio.sleep(1)
except BaseException as exc:
import pdb;pdb.set_trace()
pass
async def main():
f = asyncio.ensure_future(f1())
await asyncio.sleep(0.5)
f.cancel()
await f

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

断点处的堆栈跟踪如下所示:
(Pdb) w
/tmp/t.py(19)<module>()
-> loop.run_until_complete(main())
/usr/lib/python3.5/asyncio/base_events.py(325)run_until_complete()
-> self.run_forever()
/usr/lib/python3.5/asyncio/base_events.py(295)run_forever()
-> self._run_once()
/usr/lib/python3.5/asyncio/base_events.py(1254)_run_once()
-> handle._run()
/usr/lib/python3.5/asyncio/events.py(125)_run()
-> self._callback(*self._args)
/usr/lib/python3.5/asyncio/tasks.py(293)_wakeup()
-> self._step(exc)
/usr/lib/python3.5/asyncio/tasks.py(241)_step()
-> result = coro.throw(exc)
> /tmp/t.py(11)f2()
-> pass

这很糟糕,因为我不再看到 f2() 最初是从 f1() 调用的。

鉴于 Python 能够通过简单的单步执行,我如何检索原始调用堆栈?:
$ python3 t.py
> /tmp/t.py(11)f2()
-> pass
(Pdb) s
--Return--
> /tmp/t.py(11)f2()->None
-> pass
(Pdb) s
--Call--
> /tmp/t.py(5)f1()
-> await f2()
(Pdb) s
--Return--
> /tmp/t.py(4)f1()->None

最佳答案

没办法,抱歉。

这是不可能的,至少在 Python 3.5 中

UPD

内部 python 框架引用了外部框架 ( fr.f_back ),可以显示堆栈跟踪。

但是它没有引用等待内部协程的外部协程。

您的代码展示了一个非常有趣的案例。

举个简单的例子:

#!/usr/bin/python3
import asyncio
import sys
import traceback

async def f1():
await f2()
async def f2():
import pdb;pdb.set_trace()

loop = asyncio.get_event_loop()
loop.run_until_complete(f1())

我们将在跟踪中看到您的协程:
(Pdb) w
/tmp/3.py(12)<module>()
-> loop.run_until_complete(f1())
/usr/lib/python3.5/asyncio/base_events.py(325)run_until_complete()
-> self.run_forever()
/usr/lib/python3.5/asyncio/base_events.py(295)run_forever()
-> self._run_once()
/usr/lib/python3.5/asyncio/base_events.py(1254)_run_once()
-> handle._run()
/usr/lib/python3.5/asyncio/events.py(125)_run()
-> self._callback(*self._args)
/usr/lib/python3.5/asyncio/tasks.py(239)_step()
-> result = coro.send(None)
/tmp/3.py(7)f1()
-> await f2()
> /tmp/3.py(9)f2()->None
-> import pdb;pdb.set_trace()

但在你的情况下情况有所不同: f2()等待 sleep() .

它以以下方式在内部工作: sleep()返回一个 future 对象, f2()产生(不返回)它回到 f1()这再次产生 future 。在这种情况下,最顶层的调用者是一个任务 f创建于 main来自 ensure_future()称呼。

当您取消任务时,它会取消大多数内部服务员(由 sleep() 返回的 future ),而无需通过 f1 -> f2 -> sleep链自上而下但明确取消 sleep并以自下而上的顺序在链上弹出。

为什么您只看到堆栈中的最后一个协程——所有其他协程都会在异常展开时出现在它上面。

关于python-3.x - 调试异步函数时如何检索原始调用堆栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35376759/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com