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.
1条答案
按热度按时间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上添加了一个讨论点。