programming - python multiprocessing cpu_count



In Python, come faccio a sapere quando un processo è finito? (4)

È possibile utilizzare una queue per comunicare con i processi figli. Puoi incollare risultati intermedi su di esso, o messaggi che indicano che sono stati colpiti i traguardi (per le barre di avanzamento) o solo un messaggio che indica che il processo è pronto per essere unito. Sondare con empty è facile e veloce.

Se vuoi solo sapere se è fatto, puoi guardare il exitcode di exitcode del tuo processo o is_alive() .

https://ffff65535.com

Da all'interno di una GUI Python (PyGTK) avvio un processo (usando multiprocessing). Il processo richiede molto tempo (~ 20 minuti) per terminare. Quando il processo è finito, vorrei pulirlo (estrarre i risultati e partecipare al processo). Come faccio a sapere quando il processo è finito?

Il mio collega ha suggerito un ciclo occupato all'interno del processo genitore che controlla se il processo figlio è terminato. Sicuramente c'è un modo migliore.

In Unix, quando un processo è biforcuto, viene chiamato un gestore di segnale all'interno del processo padre al termine del processo figlio . Ma non riesco a vedere nulla di simile in Python. Mi sto perdendo qualcosa?

Com'è possibile che la fine di un processo figlio possa essere osservata all'interno del processo genitore? (Ovviamente, non voglio chiamare Process.join () poiché congelerebbe l'interfaccia della GUI.)

Questa domanda non è limitata alla multielaborazione: ho esattamente lo stesso problema con il multithreading.


Nei miei sforzi per cercare di trovare una risposta alla mia domanda, mi sono imbattuto nella funzione idle_add () di PyGTK. Questo mi dà la seguente possibilità:

  1. Crea un nuovo processo figlio che comunica tramite una coda.
  2. Crea un thread listener che ascolta la coda, quando il processo figlio invia al listener un messaggio che dice che è terminato, il listener chiama idle_add () che configura una callback.
  3. Durante la prossima volta intorno al ciclo principale, il processo genitore chiamerà il callback.
  4. Il callback può estrarre risultati, unire il processo figlio e unirsi al thread del listener.

Questo sembra un modo troppo complesso per ricreare il call-callback-when-child-process-make di Unix.

Questo deve essere un problema molto comune con le interfacce grafiche in Python. Sicuramente esiste un modello standard per risolvere questo problema?


Questa risposta è davvero semplice! (Mi ci sono voluti giorni per risolverlo.)

Combinato con idle_add () di PyGTK, puoi creare un commento AutoJoining. Il codice totale è borderline banale:

class AutoJoiningThread(threading.Thread):
    def run(self):
        threading.Thread.run(self)
        gobject.idle_add(self.join)

Se vuoi fare qualcosa in più del semplice join (come la raccolta dei risultati), puoi estendere la classe precedente per emettere i segnali al completamento, come nell'esempio seguente:

import threading
import time
import sys
import gobject
gobject.threads_init()

class Child:
    def __init__(self):
        self.result = None

    def play(self, count):
        print "Child starting to play."
        for i in range(count):
            print "Child playing."
            time.sleep(1)
        print "Child finished playing."
        self.result = 42

    def get_result(self, obj):
        print "The result was "+str(self.result)

class AutoJoiningThread(threading.Thread, gobject.GObject):
    __gsignals__ = {
        'finished': (gobject.SIGNAL_RUN_LAST,
                     gobject.TYPE_NONE,
                     ())
        }

    def __init__(self, *args, **kwargs):
        threading.Thread.__init__(self, *args, **kwargs)
        gobject.GObject.__init__(self)

    def run(self):
        threading.Thread.run(self)
        gobject.idle_add(self.join)
        gobject.idle_add(self.emit, 'finished')

    def join(self):
        threading.Thread.join(self)
        print "Called Thread.join()"

if __name__ == '__main__':
    print "Creating child"
    child = Child()
    print "Creating thread"
    thread = AutoJoiningThread(target=child.play,
                               args=(3,))
    thread.connect('finished', child.get_result)
    print "Starting thread"
    thread.start()
    print "Running mainloop (Ctrl+C to exit)"
    mainloop = gobject.MainLoop()

    try:
        mainloop.run()
    except KeyboardInterrupt:
        print "Received KeyboardInterrupt.  Quiting."
        sys.exit()

    print "God knows how we got here.  Quiting."
    sys.exit()

L'output dell'esempio sopra dipenderà dall'ordine in cui i thread sono eseguiti, ma sarà simile a:

Creating child
Creating thread
Starting thread
Child starting to play.
 Child playing.
Running mainloop (Ctrl+C to exit)
Child playing.
Child playing.
Child finished playing.
Called Thread.join()
The result was 42
^CReceived KeyboardInterrupt.  Quiting.

Non è possibile creare un AutoJoiningProcess nello stesso modo (perché non possiamo chiamare idle_add () tra due processi diversi), tuttavia possiamo usare un AutoJoiningThread per ottenere ciò che vogliamo:

class AutoJoiningProcess(multiprocessing.Process):
    def start(self):
        thread = AutoJoiningThread(target=self.start_process)
        thread.start() # automatically joins

    def start_process(self):
        multiprocessing.Process.start(self)
        self.join()

Per dimostrare AutoJoiningProcess ecco un altro esempio:

import threading
import multiprocessing
import time
import sys
import gobject
gobject.threads_init()

class Child:
    def __init__(self):
        self.result = multiprocessing.Manager().list()

    def play(self, count):
        print "Child starting to play."
        for i in range(count):
            print "Child playing."
            time.sleep(1)
    print "Child finished playing."
        self.result.append(42)

    def get_result(self, obj):
        print "The result was "+str(self.result)

class AutoJoiningThread(threading.Thread, gobject.GObject):
    __gsignals__ = {
        'finished': (gobject.SIGNAL_RUN_LAST,
                     gobject.TYPE_NONE,
                     ())
    }

    def __init__(self, *args, **kwargs):
        threading.Thread.__init__(self, *args, **kwargs)
        gobject.GObject.__init__(self)

    def run(self):
        threading.Thread.run(self)
        gobject.idle_add(self.join)
        gobject.idle_add(self.emit, 'finished')

    def join(self):
        threading.Thread.join(self)
        print "Called Thread.join()"

class AutoJoiningProcess(multiprocessing.Process, gobject.GObject):
    __gsignals__ = {
        'finished': (gobject.SIGNAL_RUN_LAST,
                     gobject.TYPE_NONE,
                     ())
        }

    def __init__(self, *args, **kwargs):
        multiprocessing.Process.__init__(self, *args, **kwargs)
        gobject.GObject.__init__(self)

    def start(self):
        thread = AutoJoiningThread(target=self.start_process)
        thread.start()

    def start_process(self):
        multiprocessing.Process.start(self)
        self.join()
        gobject.idle_add(self.emit, 'finished')

    def join(self):
        multiprocessing.Process.join(self)
        print "Called Process.join()"

if __name__ == '__main__':
    print "Creating child"
    child = Child()
    print "Creating thread"
    process = AutoJoiningProcess(target=child.play,
                               args=(3,))
    process.connect('finished',child.get_result)
    print "Starting thread"
    process.start()
    print "Running mainloop (Ctrl+C to exit)"
    mainloop = gobject.MainLoop()

    try:
        mainloop.run()
    except KeyboardInterrupt:
        print "Received KeyboardInterrupt.  Quiting."
        sys.exit()

    print "God knows how we got here.  Quiting."
    sys.exit()

L'output risultante sarà molto simile all'esempio sopra, eccetto che questa volta avremo sia l'unione dei processi sia la partecipazione dei thread del partecipante:

Creating child
Creating thread
Starting thread
Running mainloop (Ctrl+C to exit)
 Child starting to play.
Child playing.
Child playing.
Child playing.
Child finished playing.
Called Process.join()
The result was [42]
Called Thread.join()
^CReceived KeyboardInterrupt.  Quiting.

Purtroppo:

  1. Questa soluzione dipende da gobject, a causa dell'uso di idle_add (). gobject è usato da PyGTK.
  2. Questa non è una vera relazione genitore / figlio. Se uno di questi thread viene avviato da un altro thread, esso verrà comunque unito dal thread che esegue il mainloop, non il thread principale. Questo problema vale anche per AutoJoiningProcess, tranne per il fatto che immagino venga generata un'eccezione.

Pertanto, per utilizzare questo approccio, sarebbe meglio creare solo thread / processi all'interno di mainloop / GUI.


dare un'occhiata al modulo subprocess:

http://docs.python.org/library/subprocess.html

import subprocess
let pipe = subprocess.Popen("ls -l", stdout=subprocess.PIPE)
allText = pipe.stdout.read()
pipe.wait()
retVal = pipe.returncode




multiprocessing