Многопоточность python дождитесь завершения всех потоков

Возможно, это было задано в аналогичном контексте, но я не смог найти ответ после 20 минут поиска, поэтому я попрошу.

Я написал Python script (скажем: scriptA.py) и script (скажем, scriptB.py)

В scriptB Я хочу называть scriptA несколько раз с разными аргументами, каждый раз требуется около часа для запуска, (его огромный script, много вещей.. не беспокойтесь об этом), и я хочу иметь возможность запускать scriptA со всеми разными аргументами одновременно, но мне нужно дождаться, пока ВСЕ из них будут выполнены до продолжения; мой код:

import subprocess

#setup
do_setup()

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

#finish
do_finish()

Я хочу запустить все subprocess.call() в одно и то же время, а потом дождаться, когда все будет сделано, как мне это сделать?

Я попытался использовать threading, как в примере здесь:

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()

Но я не думаю, что это правильно.

Как я узнаю, что они все закончили, прежде чем перейти к моему do_finish()?

Ответ 1

Вам нужно использовать join метод объекта Thread в конце script.

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()

Таким образом, основной поток будет ждать завершения t1, t2 и t3.

Ответ 2

Поместите потоки в список, а затем используйте Способ объединения

 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()

Ответ 3

Я предпочитаю использовать понимание списка на основе списка ввода:

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]

Ответ 4

В Python3, поскольку Python 3.2 предлагает новый подход для достижения того же результата, я лично предпочитаю традиционное создание потоков /start/join, package concurrent.futures: https://docs.python.org/3/library/concurrent.futures.html

Используя ThreadPoolExecutor, код будет выглядеть следующим образом:

from concurrent.futures.thread import ThreadPoolExecutor

def call_script(arg)
    subprocess.call(scriptA + arg)

args = [argumentsA, argumentsB, argumentsC]
with ThreadPoolExecutor(max_workers=2) as executor:
    for arg in args:
        executor.submit(call_script, arg)
print('All tasks has been finished')

Одним из преимуществ является то, что вы можете контролировать пропускную способность, устанавливая максимальное количество работающих одновременно.

Ответ 5

У вас может быть класс, похожий на ниже, из которого вы можете добавить "n" количество функций или скриптов console_scripts, которые вы хотите выполнить в параллельной страсти, и начать выполнение и дождаться завершения всех заданий.

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 __name__ == '__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()

Ответ 6

Возможно, что-то вроде

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