Многопроцессорность IOError: плохая длина сообщения
Я получаю IOError: bad message length
при передаче больших аргументов функции map
. Как я могу избежать этого?
Ошибка возникает, когда я устанавливаю 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
есть функция recv_bytes
, которая вызывает IOError. Может быть, из-за этого? (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]])
Ответы
Ответ 1
Это то, что решило проблему: объявление изображений глобально.
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)
Ответ 2
Вы создаете пул и сразу отправляете все изображения в func(). Если вам удастся разобраться с одним изображением сразу, попробуйте что-то вроде этого, которое заканчивается с N = 10000 в 35 с 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)
Ответ 3
Возможно, Python загрузит ваши данные в вашу RAM-память, и вам нужно, чтобы эта память была доступна. Вы проверили использование памяти компьютера?
Также, как отметил Патрик, вы загружаете 3 ГБ данных, убедитесь, что вы используете 64-битную версию Python по мере того, как вы достигаете 32-битного ограничения памяти. Это может привести к сбою вашего процесса: 32 против 64 бит Python
Еще одним преимуществом было бы использовать python 3.4 вместо 2.7. Реализация Python 3, по-видимому, оптимизирована для очень больших диапазонов, см. Python3 против производительности списка/генератора Python2
Ответ 4
При запуске вашей программы это действительно дает мне ясную ошибку:
OSError: [Errno 12] Cannot allocate memory
Как упоминалось другими пользователями, решение вашей проблемы - просто добавить память (много) или изменить способ обработки вашей программой изображений.
Причина, по которой он использует так много памяти, заключается в том, что вы выделяете свою память для своих изображений на уровне модуля. Поэтому, когда многопроцессор развивает ваш процесс, он также копирует все изображения (которые не являются бесплатными в соответствии с объектами общей памяти в многопроцессорности python), это не обязательно, потому что вы также предоставляя изображения в качестве аргумента функции, которую мультипроцессный модуль также копирует с использованием ipc и pickle, это все равно может привести к нехватке памяти. Попробуйте одно из предлагаемых решений, предоставленное другими пользователями.