MacOS运行Python multiprocessing代码报OSError 28设备空间不足
提问:macOS运行Python multiprocessing多进程代码触发OSError: [Errno 28] No space left on device
我在macOS系统运行Python multiprocessing多进程示例代码时,触发了错误OSError: [Errno 28] No space left on device。
ENOSPC(即“设备空间不足”)错误会在I/O操作关联的数据或元数据因空间不足无法写入时触发,它不一定代表磁盘物理空间不足,也可能指逻辑空间(如最大文件长度限制)、特定数据结构空间、地址空间不足。例如vfat文件系统的目录表空间不足、inode耗尽时也会抛出该错误,大致含义为“找不到可写入的位置”。
我不理解的是,我下方的代码中并没有写入文件的操作,为什么会触发该错误?恳请大家提供帮助。
示例代码
#! /usr/bin/env python3 import sys import os import multiprocessing as mp import time def foo_pool(x): time.sleep(2) return x*x result_list = [] def log_result(result): result_list.append(result) print(result) def apply_async_with_callback(): pool = mp.Pool() for i in range(10): pool.apply_async(foo_pool, args = (i, ), callback = log_result) pool.close() pool.join() print(result_list) if __name__ == '__main__': apply_async_with_callback()
完整报错信息
python3 test.py Traceback (most recent call last): File "test.py", line 32, in <module> apply_async_with_callback() File "test.py", line 23, in apply_async_with_callback pool = mp.Pool() File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/context.py", line 119, in Pool return Pool(processes, initializer, initargs, maxtasksperchild, File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/pool.py", line 191, in __init__ self._setup_queues() File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/pool.py", line 343, in _setup_queues self._inqueue = self._ctx.SimpleQueue() File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/context.py", line 113, in SimpleQueue return SimpleQueue(ctx=self.get_context()) File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/queues.py", line 342, in __init__ self._rlock = ctx.Lock() File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/context.py", line 68, in Lock return Lock(ctx=self.get_context()) File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/synchronize.py", line 162, in __init__ SemLock.__init__(self, SEMAPHORE, 1, 1, ctx=ctx) File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/synchronize.py", line 57, in __init__ sl = self._semlock = _multiprocessing.SemLock( OSError: [Errno 28] No space left on device
回答
该错误与磁盘剩余空间无关,根因为系统POSIX信号量配额耗尽。
从报错栈可以看到,错误发生在创建_multiprocessing.SemLock对象的阶段:macOS作为BSD衍生系统,对POSIX信号量的全局分配数量有严格的默认上限。Python的multiprocessing模块初始化进程池时,会为内部的任务队列、进程同步锁创建多个POSIX信号量对象,当系统没有剩余的信号量配额可以分配时,内核就会返回ENOSPC错误,对应你看到的No space left on device提示。
ENOSPC错误本身就不只对应磁盘物理空间不足的场景,内核层面的系统资源配额耗尽也会触发该错误,和你的代码有没有写入文件的操作没有关系。
解决方案
- 最快修复:重启电脑,所有未被释放的残留信号量会被内核自动清理,绝大多数场景重启后即可正常运行代码。
- 手动清理残留信号量:
- 执行命令
ipcs -s列出当前系统所有的信号量 - 找到所有者为你当前登录用户的无用信号量条目
- 执行
ipcrm -s <信号量ID>逐个删除即可
- 执行命令
- 代码优化:
初始化进程池时不要使用默认的进程数,显式指定更小的进程数,避免一次性申请过多信号量,比如可以把pool = mp.Pool()修改为pool = mp.Pool(processes=4),进程数按需设置即可,不需要超过设备的CPU核心数。 - 永久调整配额(仅推荐专业用户操作):
可以通过修改macOS内核参数调高信号量上限,编辑/etc/sysctl.conf添加以下配置,重启后生效:kern.sysv.semmni=1024 kern.sysv.semmns=2048
内容的提问来源于stack exchange,提问作者endo.anaconda
相关产品推荐
相关产品推荐

