2010-05-31 5 views
0

J'écris un paquet Python qui lit la liste des modules (avec les données auxiliaires) à partir d'un fichier de configuration. Je veux ensuite parcourir tous les modules chargés dynamiquement et appeler une fonction do_work() qui engendrera un nouveau processus, de sorte que le code s'exécute ASYNCHRONUSUS dans un processus séparé.Chargement dynamique de modules en Python (+ question à traitement multiple)

Pour l'instant, j'importe la liste de tous les modules connus au début de mon script principal - c'est un hack méchant que je ressens, et qui n'est pas très flexible, en plus d'être une douleur de maintenance.

C'est la fonction qui génère les processus. Je vais le modifier pour charger dynamiquement le module quand il est rencontré. La clé dans le dictionnaire est le nom du module contenant le code:

def do_work(work_info): 
    for (worker, dataset) in work_info.items(): 
    #import the module defined by variable worker here... 

    # [Edit] NOT using threads anymore, want to spawn processes asynchronously here... 

    #t = threading.Thread(target=worker.do_work, args=[dataset]) 
    # I'll NOT dameonize since spawned children need to clean up on shutdown 
    # Since the threads will be holding resources 
    #t.daemon = True 
    #t.start() 

Question 1

Quand j'appelle la fonction dans mon script (comme écrit ci-dessus), je reçois l'erreur suivante:

AttributeError: 'str' object has no attribute 'do_work'

Ce qui est logique, puisque la clé du dictionnaire est une chaîne (nom du module à importer).

Quand j'ajoute la déclaration:

travailleur importation

avant la ponte du fil, je reçois l'erreur:

ImportError: No module named worker

Ceci est étrange, puisque le nom de la variable plutôt que la la valeur qu'il contient est utilisée - quand j'imprime la variable, j'obtiens la valeur (comme je m'y attends) que se passe-t-il? section

Question 2

Comme je l'ai mentionné dans le commentaire, je me rends compte que la fonction do_work() écrit dans les enfants donné naissance doit nettoyer après lui-même. Ma compréhension est d'écrire une fonction clean_up qui est appelée quand do_work() a réussi, ou une exception non gérée est attrapée - y a-t-il quelque chose de plus à faire pour que les ressources ne fuient pas ou ne quittent pas le système d'exploitation?

Question 3

Si je commente la déclaration de drapeau t.daemon, sera le code Stil ?. tourner de manière asynchrone Le travail effectué par les enfants engendrés est assez intense, et je ne veux pas avoir à attendre qu'un enfant finisse avant de pondre un autre enfant. BTW, je suis conscient que le threading en Python est en réalité, une sorte de partage de temps/tranchage - c'est ok

Enfin, y a-t-il une meilleure façon de faire ce que j'essaie de faire?

[Modifier]

Après avoir lu un peu plus sur Pythons GIL et le filetage (ahem - pirater) en Python, je pense que le mieux d'utiliser des processus séparés au lieu (au moins IIUC, le script peut prendre avantage de plusieurs processus s'ils sont disponibles), donc je vais engendrer de nouveaux processus au lieu de threads.

J'ai un exemple de code pour les processus de ponte, mais c'est un peu trivial (en utilisant les fonctions lambad). Je voudrais savoir comment l'agrandir, afin qu'il puisse gérer les fonctions d'exécution dans un module chargé (comme je le fais ci-dessus).

C'est un extrait de ce que j'ai:

def do_mp_bench(): 
    q = mp.Queue() # Not only thread safe, but "process safe" 
    p1 = mp.Process(target=lambda: q.put(sum(range(10000000)))) 
    p2 = mp.Process(target=lambda: q.put(sum(range(10000000)))) 
    p1.start() 
    p2.start() 
    r1 = q.get() 
    r2 = q.get() 
    return r1 + r2 

Comment puis-je modifier ce type pour traiter un dictionnaire de modules et exécuter une fonction do_work() dans chaque module chargé dans un nouveau processus?

Répondre

1

a été révisée à utiliser importation documentation() ici: import et refactorisé d'utiliser le module de multitraitement demandé comme indiqué ici: multiprocessing. Cela n'a pas été testé.

def do_work(work_info): 
    q = mp.Queue() 
    for (worker, dataset) in work_info.items(): 
     xworker = __import__(worker) 
     p = mp.Process(target=xworker.do_work, args=dataset).start() 
     q.put(p) 
    while not q.empty(): 
     r = q.get() 
+0

Pas besoin d'utiliser 'exec' quand vous pouvez juste utiliser' __import __() '. –

+0

n'avait aucune idée de __import __(). J'ai juste pensé à comment je le ferais avec les connaissances limitées que j'ai sur le sujet. Je vais refactoriser la réponse pour profiter des nouvelles connaissances. – Gabriel

+0

+1 pour votre effort. J'avais déjà fait cela au moment où vous avez posté votre réponse. Comme l'indique ma question modifiée, je veux générer des processus au lieu de threads maintenant. Savez-vous comment modifier votre code pour générer un processus ASYNCHRONOUSLY au lieu d'un thread? – morpheous

2

Question 1: utiliser __import__().

Question 2: pourquoi ne pas faire le nettoyage à la fin de la fonction do_work()? Question 3: Le fil démon IIRC signifie simplement que le programme n'attendra pas automatiquement la fin de ce thread.

+0

+1 pour la fonction __import __(). C'est ce dont j'avais besoin. En ce qui concerne le nettoyage, oui, je pense à faire cela, je voulais juste savoir s'il y avait autre chose à faire. En ce qui concerne la Q3, d'après ce que vous dites, commenter le drapeau démon va faire fonctionner le programme SYNCHRONE? (ce n'est PAS ce que je veux) – morpheous

+0

@morpheous: si vous démonisez le thread, vous devez utiliser explicitement la méthode 'join()' si vous voulez attendre la fin du thread. À la fin de votre programme, les threads non-démon seront automatiquement joints. C'est ce que vous voulez habituellement. Les threads sont censés fonctionner en parallèle dans les deux cas, mais à cause du GIL, ils ne le seront pas. –

+0

désolé d'être 'lent sur la prise' ici .. mais je ne comprends toujours pas exactement ce que vous dites. Je vais donc reformuler ma question (et la modifier légèrement dans le processus). Je veux exécuter un PROCESSUS enfant (Note: ne plus filer - après avoir lu plus sur le threading en Python), puis le laisser fonctionner de manière asynchrone (c'est-à-dire ne pas attendre que cela se termine). Pourriez-vous fournir un lien/extrait qui montre comment faire cela? – morpheous

Questions connexes