Multiprocessing 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)

РЕДАКТИРОВАТЬ2 Фактически я использую следующую функцию:

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]])

person Andy    schedule 14.06.2015    source источник
comment
Вы передаете 3 ГБ изображений. Если они начинаются с файловой системы, возможно, вы могли бы просто поставить в очередь имена файлов. Если вы их создаете, вы можете использовать многопроцессорный класс Array для создания данных в общей памяти, чтобы объем данных, фактически находящихся в очереди (например, информация об общей памяти), был меньше.   -  person Patrick Maupin    schedule 31.07.2015
comment
Если вы хотите избежать проблемы, вы можете заставить func загрузить соответствующее изображение, а не передавать его в качестве аргумента. Это определенно ошибка, о которой необходимо сообщить , но исправление не коснется вы скоро, и я не рекомендую использовать ночные сборки, если вы просто хотите кодировать   -  person Felipe Lema    schedule 31.07.2015
comment
Я не могу воспроизвести проблему с помощью python 2.7.10   -  person rll    schedule 31.07.2015
comment
@rll вы проверили оба фрагмента кода? сколько времени нужно, чтобы запустить программу?   -  person Andy    schedule 02.08.2015
comment
Такая же ошибка у меня на ubuntu IOError: bad message length   -  person Padraic Cunningham    schedule 03.08.2015
comment
Должен ли func () работать со всеми 1500 изображениями одновременно, или он может работать с одним изображением сразу?   -  person Joseph Sheedy    schedule 03.08.2015
comment
Чего вы пытаетесь достичь? Код, который вы даете, похоже, использует многопроцессорность без причины: он запускает единственный дочерний процесс и передает все изображения этому одному процессу. Разве вам на самом деле не нужно много дочерних процессов, каждый из которых обрабатывает одно изображение за раз?   -  person Daniel Renshaw    schedule 05.08.2015
comment
@ velotron @ Дэниел Реншоу: Я обновил свой вопрос EDIT2. Из-за проблемы с минимальным примером моя цель не была ясна. С помощью фактической функции func я вычисляю среднее значение всех изображений.   -  person Andy    schedule 05.08.2015
comment
Я добавил к своему ответу решение (без многопроцессорности). Он будет быстро обрабатывать 1500 изображений на достаточно современном оборудовании без многопроцессорной обработки.   -  person Joseph Sheedy    schedule 06.08.2015


Ответы (4)


Вы создаете пул и отправляете все изображения сразу в 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)
person Joseph Sheedy    schedule 03.08.2015
comment
Ключевым моментом здесь является то, что вам нужно закрыть и присоединиться к пулу (с pool.close() и pool.join()). - person BoltzmannBrain; 07.06.2016

Python, скорее всего, загрузит ваши данные в вашу оперативную память, и вам нужно, чтобы эта память была доступна. Вы проверили использование памяти вашего компьютера?

Также, как упоминал Патрик, вы загружаете 3 ГБ данных, убедитесь, что вы используете 64-битную версию Python, поскольку вы достигаете 32-битного ограничения памяти. Это может привести к сбою вашего процесса: 32 против 64 бит Python

Еще одно улучшение - использовать python 3.4 вместо 2.7. Реализация Python 3, похоже, оптимизирована для очень больших диапазонов, см. Производительность списка / генератора Python3 и Python2

person Community    schedule 01.08.2015

При запуске вашей программы я получаю явную ошибку:

OSError: [Errno 12] Cannot allocate memory

Как уже упоминалось другими пользователями, решение вашей проблемы - просто добавить память (много) или изменить способ обработки изображений в вашей программе.

Причина, по которой он использует так много памяти, заключается в том, что вы выделяете свою память для своих изображений на уровне модуля. Поэтому, когда многопроцессор разветвляет ваш процесс, он также копирует все изображения (что не является бесплатным в соответствии с Объекты общей памяти в многопроцессорной обработке Python), в этом нет необходимости, потому что вы также даете изображения в качестве аргумента функции, которую модуль multiprocess также копирует с помощью ipc и pickle, это все равно, вероятно, приведет к отсутствию объем памяти. Попробуйте одно из решений, предложенных другими пользователями.

person joebie13    schedule 06.08.2015

Вот что решило проблему: объявление изображений глобальными.

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)
person Andy    schedule 12.08.2015
comment
это копирует все изображения в каждый из процессов afaik, что делает этот метод очень плохим при масштабировании - person Jules G.M.; 17.05.2017