Python 在 Popen.stdout.readline 上设置超时
Python set timeout on Popen.stdout.readline
我希望能够在子进程 stdout 上设置超时,return 如果超时则为空字符串。
这是我使用 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. Its process representation 与 subprocess.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"))
我希望能够在子进程 stdout 上设置超时,return 如果超时则为空字符串。
这是我使用 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. Its process representation 与 subprocess.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"))