我在理解print
函数内部使用async
的某些限制时遇到问题。基本上这是我的代码:
#!/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 wich 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
几乎可以肯定是从stdout开始的。几乎每个命令行工具都希望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,fcntl.F_GETFL); fcntl.fcntl(sys.stdout,fcntl.F_setfL,flags&~os.O_NONBLOCK);'
我再也没有BlockingIOError
异常了,但是我不喜欢这种解决方案。
所以,我的问题是:在stdout
函数中写入async
时应该如何处理?如果我知道我正在与stdout
打交道,我应该
将stdout
设置为非阻塞并在程序退出时将其还原?有针对性的策略吗?