【发布时间】:2019-11-07 14:46:34
【问题描述】:
我无法理解在 async 函数中使用 print 的一些限制。基本上这是我的代码:
#!/usr/bin/env python
import sys
import asyncio
import aiohttp
async amain(loop):
session = aiohttp.ClientSession(loop=loop)
try:
# using session to fetch a large json file which is stored
# in obj
print(obj) # for debugging purposes
finally:
await session.close()
def main():
loop = asyncio.get_event_loop()
res = 1
try:
res = loop.run_until_complete(amain(loop, args))
except KeyboardInterrupt:
# silence traceback when pressing ctrl+c
pass
loop.close()
return res
if __name__ == '__main__':
sys.exit(main())
如果我执行此操作,则 json 对象会打印在 stdout 上,然后突然因此错误而死
$ dwd-get-sensor-file ; echo $?
Traceback (most recent call last):
File "/home/yanez/anaconda/py3/envs/mondas/bin/dwd-get-sensor-file", line 11, in <module>
load_entry_point('mondassatellite', 'console_scripts', 'dwd-get-sensor-file')()
File "/home/yanez/projects/mondassatellite/mondassatellite/mondassatellite/bin/dwd_get_sensor_file.py", line 75, in main
res = loop.run_until_complete(amain(loop, args))
File "/home/yanez/anaconda/py3/envs/mondas/lib/python3.7/asyncio/base_events.py", line 579, in run_until_complete
return future.result()
File "/home/yanez/projects/mondassatellite/mondassatellite/mondassatellite/bin/dwd_get_sensor_file.py", line 57, in amain
print(obj)
BlockingIOError: [Errno 11] write could not complete without blocking
1
有趣的是,当我执行代码时将stdout 重定向到这样的文件
$ dwd-get-sensor-file > output.txt ; echo $?
0
异常没有发生,整个输出正确重定向到output.txt。
出于测试目的,我将 json 对象转换为字符串,而不是做 print(obj) 我做 sys.stdout.write(obj_as_str) 然后我得到这个
例外:
BlockingIOError: [Errno 11] write could not complete without blocking
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
我已经搜索过这个BlockingIOError 异常,但我发现的所有线程都与网络套接字或 CI 构建有关。但是我找到了一个
有趣github comment:
make: write error几乎可以肯定是来自标准输出的 EAGAIN。几乎每个命令行工具都希望 stdout 处于阻塞模式,并且在非阻塞模式下不会正确重试。
所以当我执行这个时
python -c 'import os,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); print(flags&os.O_NONBLOCK);'
我得到 2048,这意味着阻塞(或者反过来?我很困惑)。执行后
python -c 'import os,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); fcntl.fcntl(sys.stdout, fcntl.F_SETFL, flags&~os.O_NONBLOCK);'
我不再收到 BlockingIOError 异常,但我不喜欢这个解决方案。
所以,我的问题是:在async 函数中写入stdout 时应该如何处理?如果我知道我正在处理stdout,我应该
将stdout 设置为非阻塞并在我的程序退出时将其还原?有没有具体的策略?
【问题讨论】: