1
votes

Utilisation du multitraitement avec runpy

J'ai un module Python qui utilise le multiprocessing . J'exécute ce module à partir d'un autre script avec runpy . Cependant, cela se traduit par (1) le module exécutant deux fois , et (2) les travaux de multiprocessing ne se terminent jamais (le script se bloque juste).

Dans mon travail minimal par exemple, j'ai un script runpy_test.py一:

start
done

et un répertoire module_test contenant un __init__ vide .py et un __main__.py

start
start

Lorsque j'exécute runpy_test.py , j'obtiens :

from multiprocessing import Pool

print 'start'
def f(x):
    return x*x
pool = Pool()
result = pool.map(f, [1,2,3])
print 'done'

et le script se bloque.

Si je supprime l'appel pool.map (ou si j'exécute __ main__.py directement, y compris l'appel pool.map ), j'obtiens:

import runpy
runpy.run_module('module_test')

J'exécute ceci sur Scientific Linux 7.6 en Python 2.7.5.


4 commentaires

Votre module_test semble fonctionner correctement sans supprimer pool.map pour moi.


@SreejithMenon Pour clarifier, appelez-vous le module via runpy ?


Non, j'appelle directement le module. Je me demande si l'appeler via runpy est le problème.


@SreejithMenon Désolé, j'aurais dû être plus clair. L'appel direct du module fonctionne aussi pour moi. Ce n'est que lorsque j'essaye via runpy que je rencontre ce problème.


3 Réponses :


1
votes

Essayez de définir votre fonction f dans un module séparé. Il doit être sérialisé pour être transmis aux processus du pool, puis ces processus doivent le recréer, en important le module dans lequel il se produit. Cependant, le fichier __main__.py dans lequel il se produit n'est pas un module, ou du moins pas un module bien élevé. Tenter de l'importer entraînerait la création d'un autre pool et un autre appel de la carte, ce qui semble être une recette pour un désastre.


0 commentaires

1
votes

Réécrivez votre __main__.py comme ceci:

def f(x):
    return x*x

Et puis écrivez un implementation.py (vous pouvez appeler cela comme vous want) dans lequel votre fonction est définie:

from multiprocessing import Pool
from .implementation import f

print 'start'
pool = Pool()
result = pool.map(f, [1,2,3])
print 'done'

Sinon, vous aurez le même problème avec la plupart des interfaces en multitraitement, et indépendamment de l'utilisation de runpy. Comme @Weeble l'a expliqué, lorsque Pool.map essaie de charger la fonction f dans chaque sous-processus, il importera .__ main__ où votre fonction est définie, mais comme vous avez du code exécutable au niveau du module dans __main__ , il sera réexécuté par le sous-processus.

Hormis cette raison technique, ceci est également une meilleure conception en termes de séparation des préoccupations et des tests. Vous pouvez désormais facilement importer et appeler (y compris à des fins de test) la fonction f sans l'exécuter en parallèle.


0 commentaires

0
votes

Bien que ce ne soit pas la "bonne" façon de le faire, une solution qui a fonctionné pour moi a été d'utiliser _run_module_as_main de runpy au lieu de run_module . C'était idéal pour moi car je travaillais avec le code de quelqu'un d'autre et nécessitais le moins de changements.


0 commentaires