Python 多重处理 docker alpine 中没有可用的文件描述符错误

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

OSError: [Errno 24] No file descriptors available
创建多处理队列时。仅当使用高山图像 (
FROM python:alpine3.19
) 普通图像 (
FROM python
) 工作正常时才会出现这种情况。我尝试过增加 ulimit。 默认泊坞窗设置:

"default-ulimits": {
    "nofile": {
      "Hard": 4096,
      "Name": "nofile",
      "Soft": 4096
    },
    "nproc": {
      "Hard": 4096,
      "Name": "nproc",
      "Soft": 4096
    }
  }

也在“运行”命令期间参见下文。 ulimit 设置似乎工作正常(在

/proc/1/limits
中可见)。还有其他我不知道的限制吗?

重现步骤:

Dockerfile:

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

测试.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 .
)

输出(
FROM python
):

  • 测试无文件下限
  • 按预期工作
  • 达到约128/2队列的限制

docker run -it --rm --ulimit nofile=128 test

Appending multiprocessing.Queue() n. 62 Traceback (most recent call last):
  File "/test/test.py", line 10, in <module>
    queues.append(multiprocessing.Queue())
                  ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/context.py", line 103, in Queue
    return Queue(maxsize, ctx=self.get_context())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/queues.py", line 42, in __init__
    self._reader, self._writer = connection.Pipe(duplex=False)
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 543, in Pipe
    fd1, fd2 = os.pipe()
               ^^^^^^^^^
OSError: [Errno 24] Too many open files
  • 测试高无文件限制
  • 做工精美
docker run -it --rm --ulimit nofile=4096 test

Appending multiprocessing.Queue() n. 998 ok
Appending multiprocessing.Queue() n. 999 ok
all ok

输出(
FROM python:alpine3.19
):

  • 测试无文件下限
  • 按预期工作
  • 达到约128/2队列的限制
docker run -it --rm --ulimit nofile=128 test

Appending multiprocessing.Queue() n. 62 Traceback (most recent call last):
  File "/test/test.py", line 10, in <module>
    queues.append(multiprocessing.Queue())
                  ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/context.py", line 103, in Queue
    return Queue(maxsize, ctx=self.get_context())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/queues.py", line 42, in __init__
    self._reader, self._writer = connection.Pipe(duplex=False)
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 543, in Pipe
    fd1, fd2 = os.pipe()
               ^^^^^^^^^
OSError: [Errno 24] No file descriptors available
  • 测试高无文件限制
  • 也失败了
  • 这里出了什么问题?
docker run -it --rm --ulimit nofile=4096 test

Appending multiprocessing.Queue() n. 85 Traceback (most recent call last):
  File "/test/test.py", line 10, in <module>
    queues.append(multiprocessing.Queue())
                  ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/context.py", line 103, in Queue
    return Queue(maxsize, ctx=self.get_context())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/queues.py", line 48, in __init__
    self._wlock = ctx.Lock()
                  ^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/context.py", line 68, in Lock
    return Lock(ctx=self.get_context())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/synchronize.py", line 169, in __init__
    SemLock.__init__(self, SEMAPHORE, 1, 1, ctx=ctx)
  File "/usr/local/lib/python3.12/multiprocessing/synchronize.py", line 57, in __init__
    sl = self._semlock = _multiprocessing.SemLock(
                         ^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 24] No file descriptors available

编辑:

  • 我正在从 Windows 11 运行 Docker Engine v24.0.7
  • 它在 Centos 8 上的行为相同(Docker 版本 24.0.7,构建 afdd53b)
  • 我也尝试过:
  • multiprocessing.Value(c_int, 0) -> 在 256 迭代处失败。
  • multiprocessing.Lock() -> 在 256 迭代处失败。
  • multiprocessing.Semaphore(1) -> 在 256 迭代处失败。
  • threading.Semaphore(1) -> 不会失败。
  • (multiprocessing.Pipe()) -> 不会失败。
  • multiprocessing.SimpleQueue() -> 在第 128 次迭代时失败。
  • multiprocessing.Condition() -> 在第 64 次迭代时失败。
python python-3.x docker python-multiprocessing alpine-linux
1个回答
0
投票

这个问题似乎与使用 musl 的 alpine linux 有关,而 debian 使用 glibc:实际上并不是缺少文件描述符,但是如果超过信号量的限制,POSIX-

sem_open
也可以提高
EMFILE

由于所有列出的多处理类在内部都使用信号量,因此最终会达到此限制(之前对于使用多个信号量的类)。

限制给出为

SEM_NSEMS_MAX
,并指定为 256。实际提高
EMFILE
的代码位于
sem_open

非常感谢#musl 的@psykose 向像我这样的 C 新手指出了这一点。

那么为什么它可以在 glibc / debian 上运行呢?

一般来说,

sem_open
的glibc实现不允许发生
EMFILE
,因此使用glibc根本不会出现这个问题(当然,除非系统资源耗尽)。一些进一步的信息可以在 libc-help 邮件列表上获得。

虽然我在 musl 邮件列表上发布了有关该问题的信息,但我真的不知道更改需要做多少工作以及优先级是什么。因此,目前最明智的方法可能是使用目前使用 glibc 的不同发行版。

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