You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Alpine镜像中Python多进程队列触发Errno24文件描述符不足问题

解决python:alpine3.19镜像中multiprocessing同步对象触发文件描述符耗尽问题

问题概述

在python:alpine3.19 Docker镜像中创建multiprocessing.Queue、Value、Lock、Semaphore等多进程同步对象时,频繁触发OSError: [Errno 24] No file descriptors available错误。即使调整Docker的nofile ulimit至较高值(如4096),仍然会比基于glibc的官方python镜像更早出现该错误;而线程同步对象及multiprocessing.Pipe不受影响,该问题在Windows 11(Docker Engine v24.0.7)和CentOS 8(Docker v24.0.7)上均能复现。

复现步骤

Dockerfile

# FROM python
FROM python:alpine3.19
WORKDIR test
COPY . .
CMD [ "python", "test.py"]

test.py

import multiprocessing
import time
import subprocess

if __name__ == '__main__':
    queues = []
    print((subprocess.check_output(['cat', '/proc/1/limits'])).decode())
    for i in range(1000):
        print(f"Appending multiprocessing.Queue() n. {i} ", end="")
        queues.append(multiprocessing.Queue())
        print("ok")
        time.sleep(0.1)
    print("all ok")

构建与运行命令

docker build -t test .
docker run test

测试对比结果

  • 官方python镜像:nofile限制为128时,创建到第63个队列触发错误;限制调高至4096时可完成1000个队列创建。
  • python:alpine3.19镜像:nofile限制为128时同样在第63个队列报错;限制调高至4096时仅能创建86个队列就触发错误。

原因分析

核心差异来自Alpine使用的musl libc与官方python镜像使用的glibc在进程间同步原语实现上的区别:

  • glibc下,Python的多进程同步对象依赖匿名共享内存+信号量,文件描述符占用较少;
  • musl libc对POSIX同步原语的实现会为每个同步对象分配更多的文件描述符,且默认系统信号量参数较低,进一步加剧了文件描述符耗尽的问题。

解决方案

1. 调整系统资源参数

通过Docker启动参数同时调高nofile限制和内核信号量参数,弥补musl的资源占用差异:

docker run \
  --ulimit nofile=16384:16384 \
  --sysctl kernel.sem=250 32000 32 4096 \
  test

参数说明:

  • --ulimit nofile=16384:16384:将进程的软/硬文件描述符限制调高至16384;
  • --sysctl kernel.sem=250 32000 32 4096:调整内核信号量参数,分别对应:每个进程的最大信号量数、系统范围内的最大信号量数、每个信号量集的最大信号量数、系统范围内的最大信号量集数。

2. 使用multiprocessing.Manager创建同步对象

multiprocessing.Manager通过独立的管理进程统一维护同步对象,当前进程仅通过RPC调用访问,不会直接占用自身的文件描述符:
修改test.py的队列创建逻辑:

import multiprocessing
import time
import subprocess

if __name__ == '__main__':
    # 初始化Manager
    manager = multiprocessing.Manager()
    queues = []
    print((subprocess.check_output(['cat', '/proc/1/limits'])).decode())
    for i in range(1000):
        print(f"Appending multiprocessing.Queue() n. {i} ", end="")
        # 使用Manager创建队列
        queues.append(manager.Queue())
        print("ok")
        time.sleep(0.1)
    print("all ok")

3. 切换至基于glibc的Python镜像

如果不需要Alpine镜像的轻量特性,直接使用官方python镜像(基于Debian/Ubuntu,使用glibc)即可避免该问题,同步对象的文件描述符占用效率更高。

内容的提问来源于stack exchange,提问作者Jan H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 17:25:24