Многопоточность 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()