it-swarm.com.de

python multithreading wartet, bis alle Threads fertig sind

Dies wurde möglicherweise in einem ähnlichen Zusammenhang erfragt, aber nach etwa 20 Minuten Suche konnte ich keine Antwort finden, daher werde ich fragen.

Ich habe ein Python-Skript (sagen wir: scriptA.py) und ein Skript (sagen wir scriptB.py) geschrieben.

In scriptB möchte ich scriptA mehrmals mit verschiedenen Argumenten aufrufen, jedes Mal dauert es etwa eine Stunde, um ausgeführt zu werden (es ist ein riesiges Skript, das eine Menge Sachen erledigt.. scriptA mit allen verschiedenen Argumenten gleichzeitig, aber ich muss warten, bis ALLE von ihnen fertig sind, bevor ich fortfahre; mein code:

import subprocess

#setup
do_setup()

#run scriptA
subprocess.call(scriptA + argumentsA)
subprocess.call(scriptA + argumentsB)
subprocess.call(scriptA + argumentsC)

#finish
do_finish()

Ich möchte alle subprocess.call() gleichzeitig ausführen und dann warten, bis alle fertig sind. Wie soll ich das tun? 

Ich habe versucht, Threading wie im Beispiel hier zu verwenden:

from threading import Thread
import subprocess

def call_script(args)
    subprocess.call(args)

#run scriptA   
t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))
t1.start()
t2.start()
t3.start()

Aber ich denke nicht, dass das richtig ist. 

Woher weiß ich, dass alle mit dem Laufen fertig sind, bevor ich zu meiner do_finish() gehe?

83
Inbar Rose

Sie müssen am Ende des Skripts join der Methode Thread verwenden.

t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))

t1.start()
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()

Daher wartet der Haupt-Thread, bis t1, t2 und t3 die Ausführung beenden.

117

Füge die Threads in eine Liste ein und verwende dann die Join-Methode

 threads = []

 t = Thread(...)
 threads.append(t)

 ...repeat as often as necessary...

 # Start all threads
 for x in threads:
     x.start()

 # Wait for all of them to finish
 for x in threads:
     x.join()
138
Aaron Digulla

Ich bevorzuge das Listenverständnis basierend auf einer Eingabeliste:

inputs = [scriptA + argumentsA, scriptA + argumentsB, ...]
threads = [Thread(target=call_script, args=(i)) for i in inputs]
[t.start() for t in threads]
[t.join() for t in threads]
19
Adam Matan

In Python3 gibt es seit Python 3.2 einen neuen Ansatz, um das gleiche Ergebnis zu erzielen, das ich persönlich der traditionellen Thread-Erstellung/Start/Join-Paket concurrent.futures: https://docs.python.org/3/library) bevorzuge /concurrent.futures.html

Bei Verwendung einer ThreadPoolExecutor lautet der Code:

from concurrent.futures.thread import ThreadPoolExecutor
import time

def call_script(ordinal, arg):
    print('Thread', ordinal, 'argument:', arg)
    time.sleep(2)
    print('Thread', ordinal, 'Finished')

args = ['argumentsA', 'argumentsB', 'argumentsC']

with ThreadPoolExecutor(max_workers=2) as executor:
    ordinal = 1
    for arg in args:
        executor.submit(call_script, ordinal, arg)
        ordinal += 1
print('All tasks has been finished')

Die Ausgabe des vorherigen Codes ist ungefähr so:

Thread 1 argument: argumentsA
Thread 2 argument: argumentsB
Thread 1 Finished
Thread 2 Finished
Thread 3 argument: argumentsC
Thread 3 Finished
All tasks has been finished

Einer der Vorteile ist, dass Sie den Durchsatz einstellen können, indem Sie die maximale Anzahl gleichzeitiger Mitarbeiter einstellen. 

16
Roberto

Sie können über eine Klasse wie unten verfügen, aus der Sie 'n' Anzahl von Funktionen oder console_scripts hinzufügen können, die Sie parallel ausführen möchten, die Ausführung starten und warten, bis alle Jobs abgeschlossen sind. 

from multiprocessing import Process

class ProcessParallel(object):
    """
    To Process the  functions parallely

    """    
    def __init__(self, *jobs):
        """
        """
        self.jobs = jobs
        self.processes = []

    def fork_processes(self):
        """
        Creates the process objects for given function deligates
        """
        for job in self.jobs:
            proc  = Process(target=job)
            self.processes.append(proc)

    def start_all(self):
        """
        Starts the functions process all together.
        """
        for proc in self.processes:
            proc.start()

    def join_all(self):
        """
        Waits untill all the functions executed.
        """
        for proc in self.processes:
            proc.join()


def two_sum(a=2, b=2):
    return a + b

def multiply(a=2, b=2):
    return a * b


#How to run:
if __== '__main__':
    #note: two_sum, multiply can be replace with any python console scripts which
    #you wanted to run parallel..
    procs =  ProcessParallel(two_sum, multiply)
    #Add all the process in list
    procs.fork_processes()
    #starts  process execution 
    procs.start_all()
    #wait until all the process got executed
    procs.join_all()
5
PBD

Vielleicht so etwas

for t in threading.enumerate():
    if t.daemon:
        t.join()
2
jno

Aus der threadingModuldokumentation

Es gibt ein "Hauptthread" -Objekt. das entspricht dem ersten Thread der Steuerung im Python-Programm. Es ist kein Daemon-Thread.

Es besteht die Möglichkeit, dass "Dummy-Thread-Objekte" erstellt werden . Dies sind Thread-Objekte, die "Alien-Threads" entsprechen. Dies sind Kontrollthreads, die außerhalb des Threading-Moduls gestartet wurden, z. B. direkt aus C-Code. Dummy-Thread-Objekte haben eine eingeschränkte Funktionalität; Sie gelten immer als lebendig und daemonisch und können nicht join()ed . Sie werden niemals gelöscht, da es nicht möglich ist, das .__ zu erkennen. Terminierung von außerirdischen Threads.

Um diese beiden Fälle zu erfassen, wenn Sie nicht daran interessiert sind, eine Liste der von Ihnen erstellten Threads zu führen:

import threading as thrd


def alter_data(data, index):
    data[index] *= 2


data = [0, 2, 6, 20]

for i, value in enumerate(data):
    thrd.Thread(target=alter_data, args=[data, i]).start()

for thread in thrd.enumerate():
    if thread.daemon:
        continue
    try:
        thread.join()
    except RuntimeError as err:
        if 'cannot join current thread' in err.args[0]:
            # catchs main thread
            continue
        else:
            raise

Worauf:

>>> print(data)
[0, 4, 12, 40]
0
berna1111

Ich bin gerade auf das gleiche Problem gestoßen, wo ich auf alle Threads warten musste, die mit der for-Schleife erstellt wurden. Ich habe gerade den folgenden Code ausprobiert. Vielleicht ist es nicht die perfekte Lösung, aber ich dachte, es wäre eine einfache Lösung zu testen:

for t in threading.enumerate():
    try:
        t.join()
    except RuntimeError as err:
        if 'cannot join current thread' in err:
            continue
        else:
            raise
0
Omkar