Docker Compose运行含asyncio.sleep的Python代码时打印异常求助
问题
我一直绞尽脑汁解决这个看似奇怪的问题。请参考这段Python代码:
import asyncio async def main(): print("hello") await asyncio.sleep(10) print("world") asyncio.run(main())
我希望将其作为Docker Compose服务运行,以下是我的Dockerfile:
FROM python:3.12-slim WORKDIR /app COPY ./main.py /app CMD ["python", "main.py"]
docker-compose.yaml内容如下:
version: "3.9" services: dnsgen: build: ./dnsgen
现在问题来了:当我执行docker compose up dnsgen --build --timestamps时,两个打印内容会在等待10秒后同时输出:
dnsgen-1 | 2024-02-04T01:16:25.341721172+01:00hello dnsgen-1 | 2024-02-04T01:16:25.341784837+01:00world
但在本地直接运行python main.py,或是执行docker compose run dnsgen时,都不会出现这个问题。
原因与解决办法
这是Python标准输出缓冲机制导致的差异:
- 当Python运行在非交互式终端环境(比如
docker compose up的日志捕获模式),标准输出默认启用块缓冲——print("hello")的内容会被暂存到缓冲区,直到程序结束、缓冲区满或显式刷新时才会一次性输出。 - 而
docker compose run或本地直接运行时,终端是交互式的,Python会使用行缓冲,print的内容会立即输出到终端。
解决办法有两种:
方法一:通过Python参数禁用缓冲
修改Dockerfile中的CMD命令,添加-u参数强制Python使用无缓冲的标准流:
CMD ["python", "-u", "main.py"]
方法二:在代码中显式刷新缓冲区
修改print语句,添加flush=True参数,每次打印后立即刷新缓冲区:
import asyncio async def main(): print("hello", flush=True) await asyncio.sleep(10) print("world", flush=True) asyncio.run(main())
两种方案都能解决docker compose up下日志延迟输出的问题:方法一针对容器运行环境配置,方法二让代码在任何环境下都能即时输出。
内容的提问来源于stack exchange,提问作者elaich
相关产品推荐
相关产品推荐

