Multiprocessing IOError: mauvaise longueur de message

j'obtiens un IOError: bad message length en passant de grands arguments à la fonction map . Comment puis-je éviter cela? L'erreur se produit quand je mets N=1500 ou plus.

le code est:

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)

dans les docs de multiprocessing il y a la fonction recv_bytes qui soulève une IOError. Pourrait-il être à cause de cela? ( https://python.readthedocs.org/en/v2.7.2/library/multiprocessing.html )

EDIT Si j'utilise images comme tableau de numpy au lieu d'une liste, j'obtiens une erreur différente: SystemError: NULL result without error in PyObject_Call . Un peu de code différent:

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 la fonction réelle que j'utilise est:

def func(args):
    i=args[0]
    images=args[1]
    image=np.mean(images,axis=0)
    np.savetxt("image%d.txt"%(i),image)
    return 0

en outre, le iter_args ne contiennent pas le même ensemble d'images:

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]])
21
demandé sur Andy 2015-06-14 23:23:15

4 réponses

vous créez une piscine et envoyez toutes les images à la fois à func(). Si vous pouvez vous en tirer en travaillant sur une seule image à la fois, essayez quelque chose comme ceci, qui court jusqu'à l'achèvement avec N=10000 en 35s avec Python 2.7.10 pour moi:

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

la clé ici est d'utiliser des itérateurs pour ne pas avoir à garder toutes les données en mémoire en même temps. Par exemple, j'ai converti des images à partir d'un tableau contenant toutes les données en une expression génératrice pour créer l'image uniquement lorsque nécessaire. Vous pouvez modifier ceci pour charger vos images à partir du disque ou autre. J'ai aussi utilisé la piscine.imap au lieu de pool.cartographie.

si vous le pouvez, essayez de charger les données d'image dans la fonction worker. Maintenant vous avez pour sérialiser toutes les données et de les expédier à un autre processus. Si vos données d'image sont plus grandes, cela pourrait être un goulot d'étranglement.

[mise à jour maintenant que nous savons func a à traiter toutes les images à la fois]

Vous pourriez faire un itératif sur vos images. Voici une solution sans multiprocesseur. Pour utiliser multiprocessing, vous pouvez diviser vos images en morceaux, et la ferme ces morceaux à la piscine.

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)
11
répondu velotron 2015-08-05 21:37:43

Python est susceptible de charger vos données dans votre mémoire RAM et vous avez besoin de cette mémoire pour être disponible. Avez-vous vérifié votre ordinateur utilisation de la mémoire ?

aussi comme Patrick l'a mentionné, vous chargez 3 Go de données, assurez-vous d'utiliser la version 64 bits de Python alors que vous atteignez la limite de mémoire 32 bits. Cela pourrait causer un crash de votre processus: 32 vs 64 bits Python

une Autre amélioration serait d'utiliser python 3.4 au lieu de 2.7. L'implémentation de Python 3 semble être optimisée pour de très grandes gammes, voir python3 vs python2 liste/génération de performance de la gamme

1
répondu Philippe Bruneau 2017-05-23 12:08:16

lors de l'exécution de votre programme, il me donne en fait une erreur claire:

OSError: [Errno 12] Cannot allocate memory

comme mentionné par d'autres utilisateurs, la solution à votre problème est simple ajouter de la mémoire(beaucoup) ou changer la façon dont votre programme manipule les images.

la raison pour laquelle il utilise autant de mémoire est parce que vous allouez votre mémoire pour vos images au niveau d'un module. Ainsi, lorsque multiprocess bifurque votre processus, il copie aussi toutes les images (ce qui n'est pas gratuit selon à objets de mémoire partagée en Python multiprocessing ), ce n'est pas nécessaire parce que vous donnez également les images comme argument à la fonction que le module multiprocess copie également en utilisant la CIB et pickle, cela se traduirait encore probablement par un manque de mémoire. Essayez l'une des solutions proposées donnée par les autres utilisateurs.

1
répondu joebie13 2017-05-23 11:58:53

c'est ce qui a résolu le problème: déclarer les images globales.

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)
1
répondu Andy 2015-08-12 22:04:57