此代码在Pycharm中运行没有任何问题,但当我想运行在命令提示符输出排列打乱
我有两个文件叫做test.py和test1.py其代码如下。test1.pytest.py其输出显示在test.py控制台。
test1.py
import logging
import time
logging.error(1)
time.sleep(1)
print(2)
time.sleep(1)
print(3)
time.sleep(1)
logging.error(4)
time.sleep(1)
logging.error(5)
time.sleep(1)
print(6)
test.py
import asyncio
async def _read_stream(stream, cb):
while True:
line = await stream.readline()
if line:
cb(line)
else:
break
async def _stream_subprocess(cmd, stdout_cb, stderr_cb):
process = await asyncio.create_subprocess_exec(*cmd,
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
stdout_task = asyncio.create_task(_read_stream(process.stdout, stdout_cb))
stderr_task = asyncio.create_task(_read_stream(process.stderr, stderr_cb))
await asyncio.wait([stdout_task, stderr_task])
return await process.wait()
def execute(cmd, stdout_cb, stderr_cb):
asyncio.run(_stream_subprocess(cmd, stdout_cb, stderr_cb))
if __name__ == '__main__':
print(execute(["pipenv", "run", "python", 'test1.py'],
lambda x: print("STDOUT: %s" % x),
lambda x: print("STDERR: %s" % x),))
当我运行test.py在PyCharm,程序运行正常,输出如下:
STDERR: b'ERROR:root:1rn'
STDOUT: b'2rn'
STDOUT: b'3rn'
STDERR: b'ERROR:root:4rn'
STDERR: b'ERROR:root:5rn'
STDOUT: b'6rn'
但是当我运行test.py命令提示符STDOUT未正确执行。其输出如下所示:
STDERR: b'ERROR:root:1rn'
STDERR: b'ERROR:root:4rn'
STDERR: b'ERROR:root:5rn'
STDOUT: b'2rn'
STDOUT: b'3rn'
STDOUT: b'6rn'
谁能帮我解决我的问题?问题似乎是,在一些环境中,从stdin读取已经有可用的数据,所以line = await stream.readline()
不会真正通过其他任务使asyncio循环:如果数据在那里,它只是同步返回。
所以你的stdin和stderr的任务将一个接一个地运行。
我不认为修复这个将确保你一个确定的顺序,虽然-你真的应该只是管道你的标准输入和标准错误消息到一个公共队列,而不是依赖于asyncio任务产生的消息在他们出现的顺序。
无论如何,在您的_read_stream()
函数中添加额外的asyncio.sleep
调用应该在两个环境中为您提供相同的行为:
async def _read_stream(stream, cb):
while True:
line = await stream.readline()
await asyncio.sleep(0) # Ensures the asyncio loop steps through all ready tasks
if line:
cb(line)
else:
break
是的-我也认为任何await
总是给其他任务运行的机会-上周,当回答一个类似的问题时,我发现它不是这样-检查我的更长答案:为什么发送消息到web套接字不放弃控制事件循环?