跳转到主要内容

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 (9.3 kB 查看散列)

上传时间

构建分布

awaitwhat-21.1-cp39-cp39-macosx_10_16_x86_64.whl (17.8 kB 查看散列)

上传时间 CPython 3.9 macOS 10.16+ x86-64

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面