内置打印的异步版本(stdout)

问题描述 投票:0回答:1

我在理解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,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); fcntl.fcntl(sys.stdout, fcntl.F_SETFL, flags&~os.O_NONBLOCK);'

我不再有BlockingIOError例外,但我不喜欢这种解决方案。

所以,我的问题是:在stdout函数内写入async时,应该如何处理?如果我知道我正在处理stdout,我应该将stdout设置为非阻塞,并在程序退出时将其还原?是否有特定的策略?

python-3.x python-asyncio
1个回答
0
投票

尝试aiofiles,使用stdout FD作为文件对象。

aiofiles通过引入支持将操作委派给单独的线程池的文件的异步版本来帮助解决此问题。

就实际将aiofiles直接用于FD而言,您可以使用aiofiles.os module来扩展aiofiles.os

© www.soinside.com 2019 - 2024. All rights reserved.