MagicStack / MagicStack/uvloop

OSError: [Errno 6] No such device or address: '/proc/self/fd/1' when using asyncio.create_subprocess_*

未关闭
#505 1 条评论 2 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

主要语言
Cython
星标
11.9k
派生
616
PR 合并指标
30 天内没有已合并 PR

描述

  • uvloop==0.16.0 and uvloop==0.17.0:
  • python3.8.10 and python3.10.5:
  • Platform: Ubuntu20.04:
  • Can you reproduce the bug with PYTHONASYNCIODEBUG in env? -> Yes, but there is not more output:
  • Does uvloop behave differently from vanilla asyncio? How? It uses socket instead of pipe for the file descriptors of the subprocess. This gives me an OSError6:

Uvloop does not handle subprocess pipes properly. It doesn not matter if I use asyncio.subprocess.PIPE or subprocess.PIPE. How can I access stdout/stderr of a asyncio subprocess? Is this behavior intended?

Running the proof of concept:

import asyncio, subprocess
async def poc():
    proc = await asyncio.create_subprocess_shell(
        "ls -lsh /proc/self/fd",
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    stdout, stderr = await proc.communicate()
    print(stdout, stderr)
    proc = await asyncio.create_subprocess_shell(
        "python3 -c \"f=open('/proc/self/fd/1', 'w'); f.write('test')\"", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
    )
    stdout, stderr = await proc.communicate()
    print(stdout, stderr)

async def poc1():
    proc = await asyncio.create_subprocess_shell(
        "ls -lsh /proc/self/fd",
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    stdout, stderr = await proc.communicate()
    print(stdout, stderr)
    proc = await asyncio.create_subprocess_shell(
        "python3 -c \"f=open('/proc/self/fd/1', 'w'); f.write('test')\"", stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
    stdout, stderr = await proc.communicate()
    print(stdout, stderr)

print("Default loop")
asyncio.run(poc())
asyncio.run(poc1())

import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

print("uvloop")
print("asyncio pipe")
asyncio.run(poc())
print("subprocess pipe")
asyncio.run(poc1())

Yields the following output:

Default loop
b'total 0\n0 lrwx------ 1 peter peter 64 Sep 22 12:19 0 -> /dev/pts/10\n0 l-wx------ 1 peter peter 64 Sep 22 12:19 1 -> pipe:[8435934]\n0 l-wx------ 1 peter peter 64 Sep 22 12:19 2 -> pipe:[8435935]\n0 lr-x------ 1 peter peter 64 Sep 22 12:19 3 -> /proc/625365/fd\n' b''
b'test' b''
b'total 0\n0 lrwx------ 1 peter peter 64 Sep 22 12:19 0 -> /dev/pts/10\n0 l-wx------ 1 peter peter 64 Sep 22 12:19 1 -> pipe:[8435942]\n0 l-wx------ 1 peter peter 64 Sep 22 12:19 2 -> pipe:[8435943]\n0 lr-x------ 1 peter peter 64 Sep 22 12:19 3 -> /proc/625371/fd\n' b''
b'test' b''
uvloop
asyncio pipe
b'total 0\n0 lrwx------ 1 peter peter 64 Sep 22 12:19 0 -> /dev/pts/10\n0 lrwx------ 1 peter peter 64 Sep 22 12:19 1 -> socket:[8435953]\n0 lrwx------ 1 peter peter 64 Sep 22 12:19 2 -> socket:[8435955]\n0 lr-x------ 1 peter peter 64 Sep 22 12:19 3 -> /proc/625376/fd\n' b''
b'' b'Traceback (most recent call last):\n  File "<string>", line 1, in <module>\nOSError: [Errno 6] No such device or address: \'/proc/self/fd/1\'\n'
subprocess pipe
b'total 0\n0 lrwx------ 1 peter peter 64 Sep 22 12:19 0 -> /dev/pts/10\n0 lrwx------ 1 peter peter 64 Sep 22 12:19 1 -> socket:[8396454]\n0 lrwx------ 1 peter peter 64 Sep 22 12:19 2 -> socket:[8396456]\n0 lr-x------ 1 peter peter 64 Sep 22 12:19 3 -> /proc/625380/fd\n' b''
b'' b'Traceback (most recent call last):\n  File "<string>", line 1, in <module>\nOSError: [Errno 6] No such device or address: \'/proc/self/fd/1\'\n'

As we can see, once uvloop is running the calls that worked earlier are crashing. The observable difference is that uvloop maps sockets to stdout/stderr whereas default asyncio uses pipes

贡献指南

这个仓库没有索引到贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

首先使用原生 asyncio 和 uvloop 运行提供的 proof of concept,重点关注 asyncio.create_subprocess_shell、PIPE 处理以及 uvloop.EventLoopPolicy。比较 stdout 和 stderr 文件描述符以及错误输出;当理解了报告的子进程管道行为,并且复现不再产生 OSError 时,即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
networking
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
38/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。