Python multiprocessing No file descriptors available error inside docker alpine

jaxagkaj  于 5个月前  发布在  Python
关注(0)|答案(1)|浏览(99)

OSError: [Errno 24] No file descriptors available在创建多处理队列时。仅在使用alpine image(FROM python:alpine3.19)正常image(FROM python)时才会发生。我已经尝试增加ulimit。默认docker设置:

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

字符串
在“run”命令期间也是如此,见下文。Ulimit设置似乎工作正常(在/proc/1/limits中可见)。是否还有其他我不知道的限制?

复制步骤:

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 .

输出(FROM python):

  • 测试低nofile限制
  • 按预期工作
  • 在大约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

  • 测试nofile上限
  • 工作漂亮
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):

  • 测试低nofile限制
  • 按预期工作
  • 在大约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

  • 测试nofile上限
  • 同样无法正常工作
  • 怎么了?
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,构建afdd 53 b)
  • 我也试过:
  • multiprocessing.Value(c_int,0)-> Fails at 256. iteration.
  • multiprocessing.Lock()-> Fails at 256. iteration.
  • 多处理。信号量(1)->在256次迭代时失败。
  • threading.信号量(1)->失败。
  • (multiprocessing.Pipe())->失败。
  • multiprocessing.SimpleQueue()-> Fails at 128. iteration.
  • multiprocessing.Condition()-> Fails at 64. iteration.
lbsnaicq

lbsnaicq1#

这个问题似乎与alpine Linux使用musl有关,而debian使用glibc:实际上并不是缺少文件描述符,但是如果超过了信号量的限制,POSIX- sem_open也可以引发EMFILE
由于所有列出的多处理类都在内部使用信号量,因此最终会达到此限制(对于使用多个信号量的类,会更早)。
极限为SEM_NSEMS_MAX,指定为256。实际提升EMFILE的代码在sem_open中。
非常感谢来自#musl的@psykose向像我这样的C新手指出这一点。

那么为什么它能在glibc / debian上工作呢?

一般来说,sem_open的glibc实现不允许EMFILE发生,所以使用glibc不会发生这个问题(当然,除非系统资源耗尽)。
虽然我对musl-mailinglist的问题感到困惑,但我真的不知道要做多大的改动,也不知道优先级是什么。所以目前,最明智的方法可能是使用一个不同的发行版,现在它使用的是glibc。
编辑:另一个解决方案当然是python将信号量机制改为内存信号量,如果可能的话。我在the Python Discourse上添加了一个讨论点。

相关问题