python-3.x - 内置打印 (stdout) 的异步版本

我无法理解在 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/

相关文章:

flutter - 如何为 Flutter SliverList 中的元素设置动画?

python - 如何在 Python 中移动文件?

amazon-web-services - AWS DMS - 错误 - "AWS Account

c# - 显示哪个分数与哪个标签相关的 ML.Net 错误

angularjs - 一个指令内的多个方法返回

go - 我可以防止 amqp.Channel 因错误而关闭吗?

reactjs - Material UI withStyles : Invalid prop `c

javascript - 如何仅禁用 chrome 中的 "debugger"关键字,该关键字由循环

c# - 如何检测进程是否移动了鼠标光标而不是用户?

python-3.x - matplotlib 错误 : No module named matpl