Python 在 Popen.stdout.readline 上设置超时

标签 python asynchronous coroutine

我希望能够在子进程标准输出上设置超时,并在超时时返回一个空字符串。

这是我使用 asyncio 进行的尝试。

但是,它在 asyncio.wait_for 中使用 file.stdout.readline() 失败。

知道如何解决这个问题吗?

import threading
import select
import subprocess
import queue
import time
import asyncio

class collector():
    @staticmethod
    async def readline(file, timeout=3):
        try:
            line = await asyncio.wait_for(file.stdout.readline(), timeout)
        except asyncio.TimeoutError:
            return ""
        else:
            return line

    @staticmethod
    async def background(command):
        f = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        while True:
            line = await collector.readline(file=f, timeout=3)



asyncio.run(collector.background("tail -f /tmp/2222"))

这里是调用栈:

  File "/tmp/script.py", line 13, in readline
    line = await asyncio.wait_for(file.stdout.readline(), timeout)
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/tasks.py", line 462, in wait_for
    fut = ensure_future(fut, loop=loop)
  File "/usr/local/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/tasks.py", line 679, in ensure_future
    raise TypeError('An asyncio.Future, a coroutine or an awaitable is '
TypeError: An asyncio.Future, a coroutine or an awaitable is required

最佳答案

subprocess 库只提供同步函数。 asyncio 不能直接使用这些,手动包装它们效率低下。

asyncio 已经附带了 its own subprocess backend .它的process representationsubprocess.Popen 类似,但允许协作等待操作。

import asyncio.subprocess

async def background(*command):
    # create subprocess via asyncio
    proc = await asyncio.create_subprocess_exec(
        *command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
    )
    while True:
        line = await readline(proc.stdout, timeout=0.01)
        print("read", len(line), "characters")

# read from an async stream vvvvvvvvvvvvvvvvvv instead of a file-like object
async def readline(stream: asyncio.StreamReader, timeout: float):
    try:
        # stream.readline is a coroutine vvvvvvvvvvvv
        return await asyncio.wait_for(stream.readline(), timeout=timeout)
    except asyncio.TimeoutError:
        return ""


asyncio.run(background("cat", "/dev/random"))

关于Python 在 Popen.stdout.readline 上设置超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68561211/

相关文章:

python - tkinter python : catching exceptions

python - 将 PDF 数据抓取到 Excel *绝对初学者*

python - 异步: why isn't it non-blocking by default

lua - 如何从函数外部停止 Lua 协程?

python - 在 python 中转发 kwargs

python - 如何将多个网格节点附加到 blender 中的一个对象?

asynchronous - 如何使用 Chilkat 作为异步通过 VB6 从网站获取数据?

python - Tornado 的同步行为

kotlin - 在哪些情况下您不想要或不应该在 Kotlin 中使用协程?

kotlin - 应使用 CoroutineScope 的扩展函数或挂起函数