Multiprocessing IOError: bad message length
Multiprocessing IOError: bad message length
将大参数传递给 map
函数时,我得到一个 IOError: bad message length
。我怎样才能避免这种情况?
当我设置 N=1500
或更大时出现错误。
密码是:
import numpy as np
import multiprocessing
def func(args):
i=args[0]
images=args[1]
print i
return 0
N=1500 #N=1000 works fine
images=[]
for i in np.arange(N):
images.append(np.random.random_integers(1,100,size=(500,500)))
iter_args=[]
for i in range(0,1):
iter_args.append([i,images])
pool=multiprocessing.Pool()
print pool
pool.map(func,iter_args)
在 multiprocessing
的文档中有一个引发 IOError 的函数 recv_bytes
。难道是因为这个? (https://python.readthedocs.org/en/v2.7.2/library/multiprocessing.html)
编辑
如果我使用 images
作为 numpy 数组而不是列表,我会得到一个不同的错误:SystemError: NULL result without error in PyObject_Call
。
有点不同的代码:
import numpy as np
import multiprocessing
def func(args):
i=args[0]
images=args[1]
print i
return 0
N=1500 #N=1000 works fine
images=[]
for i in np.arange(N):
images.append(np.random.random_integers(1,100,size=(500,500)))
images=np.array(images) #new
iter_args=[]
for i in range(0,1):
iter_args.append([i,images])
pool=multiprocessing.Pool()
print pool
pool.map(func,iter_args)
EDIT2 我实际使用的函数是:
def func(args):
i=args[0]
images=args[1]
image=np.mean(images,axis=0)
np.savetxt("image%d.txt"%(i),image)
return 0
此外,iter_args
不包含同一组图像:
iter_args=[]
for i in range(0,1):
rand_ind=np.random.random_integers(0,N-1,N)
iter_args.append([i,images[rand_ind]])
Python 可能会将您的数据加载到您的 RAM 内存中,您需要此内存可用。您是否检查过您的计算机内存使用情况?
此外,正如帕特里克提到的,您正在加载 3GB 的数据,请确保您使用 64 位版本的 Python,因为您将达到 32 位内存限制。这可能会导致您的进程崩溃:32 vs 64 bits Python
另一个改进是使用 python 3.4 而不是 2.7。 Python 3 实现似乎针对非常大的范围进行了优化,请参阅 Python3 vs Python2 list/generator range performance
您正在创建一个池并将所有图像一次发送到 func()。如果您可以一次处理单个图像,请尝试这样的操作,它在 35 秒内以 N=10000 运行完成,对我来说 Python 2.7.10:
import numpy as np
import multiprocessing
def func(args):
i = args[0]
img = args[1]
print "{}: {} {}".format(i, img.shape, img.sum())
return 0
N=10000
images = ((i, np.random.random_integers(1,100,size=(500,500))) for i in xrange(N))
pool=multiprocessing.Pool(4)
pool.imap(func, images)
pool.close()
pool.join()
这里的关键是使用迭代器,这样您就不必一次将所有数据保存在内存中。例如,我将包含所有数据的数组中的图像转换为生成器表达式,以便仅在需要时创建图像。您可以修改它以从磁盘或其他任何地方加载图像。我还使用 pool.imap 而不是 pool.map。
如果可以,请尝试在辅助函数中加载图像数据。现在您必须序列化所有数据并将其传送到另一个进程。如果您的图像数据较大,这可能是一个瓶颈。
[现在更新,我们知道 func 必须一次处理所有图像]
您可以对图像进行迭代平均。这是一个不使用多处理的解决方案。要使用多处理,您可以将图像分成块,然后将这些块分配到池中。
import numpy as np
N=10000
shape = (500,500)
def func(images):
average = np.full(shape, 0)
for i, img in images:
average += img / N
return average
images = ((i, np.full(shape,i)) for i in range(N))
print func(images)
当 运行 你的程序实际上给了我一个明确的错误:
OSError: [Errno 12] Cannot allocate memory
正如其他用户所提到的,您的问题的解决方案是简单地添加内存(很多)或更改程序处理图像的方式。
它使用这么多内存的原因是因为您在模块级别为图像分配了内存。因此,当多进程分叉您的进程时,它还会复制所有图像(根据Shared-memory objects in python multiprocessing,这不是免费的),这是没有必要的,因为您还将图像作为多进程模块也复制的函数的参数使用 ipc 和 pickle,这仍然可能导致内存不足。尝试其他用户提供的建议解决方案之一。
这就是解决问题的方法:将图像声明为全局图像。
import numpy as np
import multiprocessing
N=1500 #N=1000 works fine
images=[]
for i in np.arange(N):
images.append(np.random.random_integers(1,100,size=(500,500)))
def func(args):
i=args[0]
images=images
print i
return 0
iter_args=[]
for i in range(0,1):
iter_args.append([i])
pool=multiprocessing.Pool()
print pool
pool.map(func,iter_args)
传递大型对象时得到 IOError: bad message length
的原因是旧 CPython 版本(3.2 及更早版本)的硬编码限制为 0x7fffffff 字节或大约 2.1GB:https://github.com/python/cpython/blob/v2.7.5/Modules/_multiprocessing/multiprocessing.h#L182
此 CPython 变更集(在 CPython 3.3 及更高版本中)删除了硬编码限制:https://github.com/python/cpython/commit/87cf220972c9cb400ddcd577962883dcc5dca51a#diff-4711c9abeca41b149f648d4b3c15b6a7d2baa06aa066f46359e4498eb8e39f60L182
将大参数传递给 map
函数时,我得到一个 IOError: bad message length
。我怎样才能避免这种情况?
当我设置 N=1500
或更大时出现错误。
密码是:
import numpy as np
import multiprocessing
def func(args):
i=args[0]
images=args[1]
print i
return 0
N=1500 #N=1000 works fine
images=[]
for i in np.arange(N):
images.append(np.random.random_integers(1,100,size=(500,500)))
iter_args=[]
for i in range(0,1):
iter_args.append([i,images])
pool=multiprocessing.Pool()
print pool
pool.map(func,iter_args)
在 multiprocessing
的文档中有一个引发 IOError 的函数 recv_bytes
。难道是因为这个? (https://python.readthedocs.org/en/v2.7.2/library/multiprocessing.html)
编辑
如果我使用 images
作为 numpy 数组而不是列表,我会得到一个不同的错误:SystemError: NULL result without error in PyObject_Call
。
有点不同的代码:
import numpy as np
import multiprocessing
def func(args):
i=args[0]
images=args[1]
print i
return 0
N=1500 #N=1000 works fine
images=[]
for i in np.arange(N):
images.append(np.random.random_integers(1,100,size=(500,500)))
images=np.array(images) #new
iter_args=[]
for i in range(0,1):
iter_args.append([i,images])
pool=multiprocessing.Pool()
print pool
pool.map(func,iter_args)
EDIT2 我实际使用的函数是:
def func(args):
i=args[0]
images=args[1]
image=np.mean(images,axis=0)
np.savetxt("image%d.txt"%(i),image)
return 0
此外,iter_args
不包含同一组图像:
iter_args=[]
for i in range(0,1):
rand_ind=np.random.random_integers(0,N-1,N)
iter_args.append([i,images[rand_ind]])
Python 可能会将您的数据加载到您的 RAM 内存中,您需要此内存可用。您是否检查过您的计算机内存使用情况?
此外,正如帕特里克提到的,您正在加载 3GB 的数据,请确保您使用 64 位版本的 Python,因为您将达到 32 位内存限制。这可能会导致您的进程崩溃:32 vs 64 bits Python
另一个改进是使用 python 3.4 而不是 2.7。 Python 3 实现似乎针对非常大的范围进行了优化,请参阅 Python3 vs Python2 list/generator range performance
您正在创建一个池并将所有图像一次发送到 func()。如果您可以一次处理单个图像,请尝试这样的操作,它在 35 秒内以 N=10000 运行完成,对我来说 Python 2.7.10:
import numpy as np
import multiprocessing
def func(args):
i = args[0]
img = args[1]
print "{}: {} {}".format(i, img.shape, img.sum())
return 0
N=10000
images = ((i, np.random.random_integers(1,100,size=(500,500))) for i in xrange(N))
pool=multiprocessing.Pool(4)
pool.imap(func, images)
pool.close()
pool.join()
这里的关键是使用迭代器,这样您就不必一次将所有数据保存在内存中。例如,我将包含所有数据的数组中的图像转换为生成器表达式,以便仅在需要时创建图像。您可以修改它以从磁盘或其他任何地方加载图像。我还使用 pool.imap 而不是 pool.map。
如果可以,请尝试在辅助函数中加载图像数据。现在您必须序列化所有数据并将其传送到另一个进程。如果您的图像数据较大,这可能是一个瓶颈。
[现在更新,我们知道 func 必须一次处理所有图像]
您可以对图像进行迭代平均。这是一个不使用多处理的解决方案。要使用多处理,您可以将图像分成块,然后将这些块分配到池中。
import numpy as np
N=10000
shape = (500,500)
def func(images):
average = np.full(shape, 0)
for i, img in images:
average += img / N
return average
images = ((i, np.full(shape,i)) for i in range(N))
print func(images)
当 运行 你的程序实际上给了我一个明确的错误:
OSError: [Errno 12] Cannot allocate memory
正如其他用户所提到的,您的问题的解决方案是简单地添加内存(很多)或更改程序处理图像的方式。
它使用这么多内存的原因是因为您在模块级别为图像分配了内存。因此,当多进程分叉您的进程时,它还会复制所有图像(根据Shared-memory objects in python multiprocessing,这不是免费的),这是没有必要的,因为您还将图像作为多进程模块也复制的函数的参数使用 ipc 和 pickle,这仍然可能导致内存不足。尝试其他用户提供的建议解决方案之一。
这就是解决问题的方法:将图像声明为全局图像。
import numpy as np
import multiprocessing
N=1500 #N=1000 works fine
images=[]
for i in np.arange(N):
images.append(np.random.random_integers(1,100,size=(500,500)))
def func(args):
i=args[0]
images=images
print i
return 0
iter_args=[]
for i in range(0,1):
iter_args.append([i])
pool=multiprocessing.Pool()
print pool
pool.map(func,iter_args)
传递大型对象时得到 IOError: bad message length
的原因是旧 CPython 版本(3.2 及更早版本)的硬编码限制为 0x7fffffff 字节或大约 2.1GB:https://github.com/python/cpython/blob/v2.7.5/Modules/_multiprocessing/multiprocessing.h#L182
此 CPython 变更集(在 CPython 3.3 及更高版本中)删除了硬编码限制:https://github.com/python/cpython/commit/87cf220972c9cb400ddcd577962883dcc5dca51a#diff-4711c9abeca41b149f648d4b3c15b6a7d2baa06aa066f46359e4498eb8e39f60L182