我无法理解在 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 :
The
make: write error
is almost certainly EAGAIN from stdout. Pretty much every command line tool expects stdout to be in blocking mode, and does not properly retry when in nonblocking mode.
所以当我执行这个
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
设置为非阻塞并在我的程序退出时将其还原?对此有具体的策略吗?
最佳答案
给aiofiles尝试使用 stdout FD 作为文件对象。
aiofiles helps with this by introducing asynchronous versions of files that support delegating operations to a separate thread pool.
就直接将 aiofiles
与 FD 一起使用而言,您可能可以扩展 aiofiles.os
module , 使用 wrap(os.write)
。
https://stackoverflow.com/questions/58751221/