async/await 反省
项目描述
Await, What?
告诉你在异步/await程序中什么等待什么。
Python 3.10.0a1
看起来在3.10中API已更改,C扩展无法编译。我会调查...
Alpine
您需要 apk add build-base openssl-dev libffi-dev
2019 Sprint 设置
通讯: https://gitter.im/awaitwhat/community
- Python 3.9, Python 3.8(首选)或Python 3.7
- 您的平台开发工具(编译器等)。
- 确保
python
是3.9或3.8或3.7。 - 安装
poetry
- 安装
graphviz
- 克隆此仓库
- 查看 测试
- 查看 问题
> python --version
Python 3.9.0b4 #🧡
Python 3.8.4 #👌
> dot -V
dot - graphviz version 2.40.1
> curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python
# add ~/.poetry/bin to your PATH
> git clone git@github.com:dimaqq/awaitwhat.git
> cd awaitwhat
~/awaitwhat (dev|✔) > poetry shell # creates a venv and drops you in it
(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > poetry install # installs projects dependencies in a venv
(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > poetry build # builds a C extension in this project
(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > env PYTHONPATH=. python examples/test_shield.py | tee graph.dot
(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > dot -Tsvg graph.dot -o graph.svg
(awaitwhat-x-py3.9) ~/awaitwhat (dev|✔) > open graph.svg # or load it in a browser
TL;DR
假设您有这段代码
async def job():
await foo()
async def foo():
await bar()
async def bar():
await baz()
async def baz():
await leaf()
async def leaf():
await asyncio.sleep(1) # imagine you don't know this
async def work():
await asyncio.gather(..., job())
现在这段代码卡住了,您想知道为什么。
Python 内置
Stack for <Task pending coro=<job() …> wait_for=<Future pending cb=[<TaskWakeupMethWrapper …>()]> cb=[…]> (most recent call last):
File "test/test_stack.py", line 34, in job
await foo()
这个库
Stack for <Task pending coro=<job() …> wait_for=<Future pending cb=[<TaskWakeupMethWrapper …>()]> cb=[…]> (most recent call last):
File "test/test_stack.py", line 34, in job
await foo()
File "test/test_stack.py", line 38, in foo
await bar()
File "test/test_stack.py", line 42, in bar
await baz()
File "test/test_stack.py", line 46, in baz
await leaf()
File "test/test_stack.py", line 50, in leaf
await asyncio.sleep(1)
File "/…/asyncio/tasks.py", line 568, in sleep
return await future
File "<Sentinel>", line 0, in <_asyncio.FutureIter object at 0x7fb6981690d8>: …
依赖图
参考
https://mail.python.org/archives/list/async-sig@python.org/thread/6E2LRVLKYSMGEAZ7OYOYR3PMZUUYSS3K/
Hi group,
I'm recently debugging a long-running asyncio program that appears to get stuck about once a week.
迄今为止我发现的工具是
- 高级:
asyncio.all_tasks()
+asyncio.Task.get_stack()
- 低级:
loop._selector._fd_to_key
缺少的是中间层,即等待什么堆栈样式的链接。例如,考虑以下内容
async def leaf(): await somesocket.recv() async def baz(): await leaf() async def bar(): await baz() async def foo(): await bar() async def job(): await foo() async def work(): await asyncio.gather(..., job()) async def main(): asyncio.run(work())任务堆栈将包含
- 带行号的工作主体和主体
- 指向foo的带行号的作业任务
文件描述符映射,套接字fd,
loop._recv()
和一个Future
。缺少的是连接
foo->bar->baz->leaf
。也就是说,我无法知道哪个任务正在等待哪个终端Future
。这个问题有没有我还没有意识到的解决方案?有没有现成的库或外部工具?
也许,如果我能够获取所有待处理的协程的列表,我就可以找出问题所在。
如果没有这样的API,我正在考虑以下方案
async def foo(): await bar() In [37]: dis.dis(foo) 1 0 LOAD_GLOBAL 0 (bar) 2 CALL_FUNCTION 0 4 GET_AWAITABLE 6 LOAD_CONST 0 (None) 8 YIELD_FROM 10 POP_TOP 12 LOAD_CONST 0 (None) 14 RETURN_VALUE从一个待处理的任务开始,我会获取它的协程,
获取协程帧,如果当前指令是
YIELD_FROM
,那么对可等待对象的引用应该在堆栈顶部。如果这个引用指向一个待处理的协程,我将将其添加到“正向跟踪”中,并重复。在某个时刻,我会遇到一个不是待处理协程的可等待对象,这可能是一个其他
Task
(我已经得到了这些),一个低级Future
(可以在事件循环中查找),一个Event
(很遗憾,应该在创建时记录所有Event
)或其他十几个特殊情况。大家对这个方法怎么看?
谢谢,D。
项目详情
awaitwhat-21.1.tar.gz的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 4c84ab717d1781c7ce01fcaa51cef35a63a10f3ce8f64609c8294c0fc6b6ae99 |
|
MD5 | 97a21d53e67f573eb70fa29d0312eda5 |
|
BLAKE2b-256 | 08fd2c94a7ed767a24c73f1c85016825a1474d2f2ba27168658af81173d8068e |
awaitwhat-21.1-cp39-cp39-macosx_10_16_x86_64.whl的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | dc2c534603878d44947511565fa638aa9af1b247a58cd2d6290def247372fd33 |
|
MD5 | 85cbae56be6177029d9e2c0d1108b61c |
|
BLAKE2b-256 | bb81d0cdd07d4256cda4463dbec4a912d2f6a3947b7db97b9f986d0147fea222 |