2016-07-15 2 views
2

Hier, j'ai posé une question: Reading data in parallel with multiprocessRemplir un dictionnaire en parallèle avec multitraitement

Je suis très bonnes réponses, et j'implémenté la solution mentionnée dans la réponse que je marqué comme correct.

def read_energies(motif): 
    os.chdir("blabla/working_directory") 
    complx_ener = pd.DataFrame() 
    # complex function to fill that dataframe 
    lig_ener = pd.DataFrame() 
    # complex function to fill that dataframe 
    return motif, complx_ener, lig_ener 

COMPLEX_ENERGIS = {} 
LIGAND_ENERGIES = {} 
p = multiprocessing.Pool(processes=CPU) 
for x in p.imap_unordered(read_energies, peptide_kd.keys()): 
    COMPLEX_ENERGIS[x[0]] = x[1] 
    LIGAND_ENERGIES[x[0]] = x[2] 

Cependant, cette solution prend la même quantité de temps que si je voudrais juste itérer sur peptide_kd.keys() et remplir le DataFrames un par un. Pourquoi est-ce si? Y a-t-il un moyen de remplir les dicts désirés en parallèle et d'obtenir une augmentation de vitesse? Je l'utilise sur un HPC 48 core.

+0

Il se peut que le surcoût lié à l'utilisation du multitraitement soit supérieur à celui du traitement de la fonction complexe. Peut-être que le fait d'avoir 'read_energies()' traiter un dataframe à nombre variable à chaque fois vous permettrait de régler les choses au point où cela deviendrait avantageux. – martineau

Répondre

3

Vous encourez une bonne quantité de frais généraux dans (1) le démarrage de chaque processus, et (2) avoir à copier le pandas.DataFrame (et etc) à travers plusieurs processus. Si vous avez juste besoin d'avoir un dict rempli en parallèle, je suggère d'utiliser une mémoire partagée dict. Si aucune clé n'est écrasée, alors c'est facile et vous n'avez pas à vous soucier des verrous.

(Note J'utilise multiprocess ci-dessous, qui est une fourchette de multiprocessing - mais seulement je peux démontrer de l'interprète, sinon, vous auriez à faire le dessous de __main__).

>>> from multiprocess import Process, Manager 
>>> 
>>> def f(d, x): 
... d[x] = x**2 
... 
>>> manager = Manager() 
>>> d = manager.dict() 
>>> job = [Process(target=f, args=(d, i)) for i in range(5)] 
>>> _ = [p.start() for p in job] 
>>> _ = [p.join() for p in job] 
>>> print d 
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16} 

Cette solution ne permet pas de copies des dict à partager entre les processus, de sorte qu'une partie des frais généraux est réduite. Pour les objets de grande taille comme un pandas.DataFrame, il peut être significatif par rapport au coût d'une opération simple comme x**2. De même, engendrer un Process peut prendre du temps, et vous pouvez peut-être faire ce qui précède encore plus rapidement (pour les objets légers) en utilisant des threads (par exemple multiprocess.dummy au lieu de multiprocess pour votre solution originale ou la mienne ci-dessus).

Si vous faites besoin de partager DataFrames (comme votre code suggère plutôt comme la question demande), vous pourriez être en mesure de le faire en créant une mémoire partagée numpy.ndarray.

+0

Merci pour la réponse! Je vais essayer cela maintenant, mais d'abord je voudrais demander quelque chose. Je ne comprends pas la différence entre les dataframes 'shared' mentionnées (variables je suppose). Pourquoi mon code implique-t-il que j'utilise un DataFrame partagé? Le travail que je veux faire en parallèle est comme vous l'avez décrit, remplir un dictionnaire, et l'utiliser par la suite de différentes manières (lire les données à l'intérieur), mais ne rien changer à l'intérieur. –

+0

La raison pour laquelle j'ai dit que vous pourriez regarder dans les tableaux de mémoire partagée est que vous renvoyez deux instances 'DataFrame' de chaque' Process'. Cependant, il est difficile de vous indiquer si vous devez le faire ou non, car vous n'avez présenté que du méta-code. –

+0

Ohh je vois. J'ai besoin des deux 'DataFrames'. Est-ce problématique de renvoyer deux d'entre eux? Serait-il plus facile de le faire en deux étapes distinctes? –