Multiprocess and Multiprocessing with no file IO: OSError: [Errno 24] Too many open files
Multiprocess and Multiprocessing with no file IO: OSError: [Errno 24] Too many open files
总结:
我正在尝试使用 multiprocess 和 multiprocessing 来并行处理具有以下属性的工作:
- 共享数据结构
- 传递给函数的多个参数
- 根据当前系统设置进程数
错误:
我的方法适用于少量工作,但在执行较大任务时会失败:
OSError: [Errno 24] Too many open files
尝试过的解决方案
运行 在 macOS Catalina 系统上,ulimit -n
在 Pycharm.
内给出 1024
有没有办法避免必须更改 ulimit
?我想避免这种情况,因为代码对于各种系统来说都是开箱即用的。
我在 this thread 等相关问题中看到建议在评论中使用 .join 和 gc.collect,其他线程建议关闭所有打开的文件,但我不访问我的代码中的文件。
import gc
import time
import numpy as np
from math import pi
from multiprocess import Process, Manager
from multiprocessing import Semaphore, cpu_count
def do_work(element, shared_array, sema):
shared_array.append(pi*element)
gc.collect()
sema.release()
# example_ar = np.arange(1, 1000) # works
example_ar = np.arange(1, 10000) # fails
# Parallel code
start = time.time()
# Instantiate a manager object and a share a datastructure
manager = Manager()
shared_ar = manager.list()
# Create semaphores linked to physical cores on a system (1/2 of reported cpu_count)
sema = Semaphore(cpu_count()//2)
job = []
# Loop over every element and start a job
for e in example_ar:
sema.acquire()
p = Process(target=do_work, args=(e, shared_ar, sema))
job.append(p)
p.start()
_ = [p.join() for p in job]
end_par = time.time()
# Serial code equivalent
single_ar = []
for e in example_ar:
single_ar.append(pi*e)
end_single = time.time()
print(f'Parallel work took {end_par-start} seconds, result={sum(list(shared_ar))}')
print(f'Serial work took {end_single-end_par} seconds, result={sum(single_ar)}')
避免更改 ulimit 的方法是确保您的进程池大小不会增加到超过 1024。这就是为什么 1000 有效而 10000 失败的原因。
这是一个使用池管理进程的示例,它将确保您不会超过 ulimit 值的上限:
from multiprocessing import Pool
def f(x):
return x*x
if __name__ == '__main__':
with Pool(5) as p:
print(p.map(f, [1, 2, 3]))
https://docs.python.org/3/library/multiprocessing.html#introduction
other threads recommend closing any opened files but I do not access
files in my code
您没有打开文件,但您的进程正在打开文件描述符,这就是 OS 在这里看到的。
检查文件描述符的数量限制。我将 ulimit 从 1024
更改为 4096
并且它起作用了。
检查:
ulimit -n
对我来说是 1024
,我将其更新为 4096
并且有效。
ulimit -n 4096
总结:
我正在尝试使用 multiprocess 和 multiprocessing 来并行处理具有以下属性的工作:
- 共享数据结构
- 传递给函数的多个参数
- 根据当前系统设置进程数
错误:
我的方法适用于少量工作,但在执行较大任务时会失败:
OSError: [Errno 24] Too many open files
尝试过的解决方案
运行 在 macOS Catalina 系统上,ulimit -n
在 Pycharm.
1024
有没有办法避免必须更改 ulimit
?我想避免这种情况,因为代码对于各种系统来说都是开箱即用的。
我在 this thread 等相关问题中看到建议在评论中使用 .join 和 gc.collect,其他线程建议关闭所有打开的文件,但我不访问我的代码中的文件。
import gc
import time
import numpy as np
from math import pi
from multiprocess import Process, Manager
from multiprocessing import Semaphore, cpu_count
def do_work(element, shared_array, sema):
shared_array.append(pi*element)
gc.collect()
sema.release()
# example_ar = np.arange(1, 1000) # works
example_ar = np.arange(1, 10000) # fails
# Parallel code
start = time.time()
# Instantiate a manager object and a share a datastructure
manager = Manager()
shared_ar = manager.list()
# Create semaphores linked to physical cores on a system (1/2 of reported cpu_count)
sema = Semaphore(cpu_count()//2)
job = []
# Loop over every element and start a job
for e in example_ar:
sema.acquire()
p = Process(target=do_work, args=(e, shared_ar, sema))
job.append(p)
p.start()
_ = [p.join() for p in job]
end_par = time.time()
# Serial code equivalent
single_ar = []
for e in example_ar:
single_ar.append(pi*e)
end_single = time.time()
print(f'Parallel work took {end_par-start} seconds, result={sum(list(shared_ar))}')
print(f'Serial work took {end_single-end_par} seconds, result={sum(single_ar)}')
避免更改 ulimit 的方法是确保您的进程池大小不会增加到超过 1024。这就是为什么 1000 有效而 10000 失败的原因。
这是一个使用池管理进程的示例,它将确保您不会超过 ulimit 值的上限:
from multiprocessing import Pool
def f(x):
return x*x
if __name__ == '__main__':
with Pool(5) as p:
print(p.map(f, [1, 2, 3]))
https://docs.python.org/3/library/multiprocessing.html#introduction
other threads recommend closing any opened files but I do not access files in my code
您没有打开文件,但您的进程正在打开文件描述符,这就是 OS 在这里看到的。
检查文件描述符的数量限制。我将 ulimit 从 1024
更改为 4096
并且它起作用了。
检查:
ulimit -n
对我来说是 1024
,我将其更新为 4096
并且有效。
ulimit -n 4096