Подтвердить что ты не робот

Многопроцессорность 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]])
4b9b3361

Ответ 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, это все равно может привести к нехватке памяти. Попробуйте одно из предлагаемых решений, предоставленное другими пользователями.