Запускать процесс за процессом в очереди, используя python - PullRequest
0 голосов
/ 20 сентября 2019

У меня есть очередь из 500 процессов, которые я хочу запустить через скрипт Python, я хочу запускать все N процессов параллельно.

Что мой скрипт Python делает до сих пор: он запускает N процессов параллельно, ожидает завершения всех из них, затем запускает следующие N файлов.

Что мне нужно сделать: Когда один из N процессов завершен, автоматически запускается другой процесс из очереди, не ожидаяостальные процессы завершаются.

Примечание: я не знаю, сколько времени займет каждый процесс, поэтому я не могу запланировать запуск процесса в определенное время.

код, который у меня есть.В настоящее время я использую subprocess.Popen, но я не ограничен его использованием.

for i in range(0, len(queue), N):
    batch = []
    for _ in range(int(jobs)):
        batch.append(queue.pop(0))
    for process in batch:
        p = subprocess.Popen([process])
        ps.append(p)
    for p in ps:
        p.communicate()

Ответы [ 2 ]

1 голос
/ 20 сентября 2019

Предполагая python3 , вы можете использовать ThreadPoolExecutor из concurrent.futures как,

$ cat run.py
from subprocess import Popen, PIPE
from concurrent.futures import ThreadPoolExecutor


def exec_(cmd):
    proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
    stdout, stderr = proc.communicate()
    #print(stdout, stderr)


def main():
    with ThreadPoolExecutor(max_workers=4) as executor:
        # to demonstrate it will take a batch of 4 jobs at the same time
        cmds = [['sleep', '4'] for i in range(10)]
        start = time.time()
        futures = executor.map(exec_, cmds)
        for future in futures:
            pass
        end = time.time()
        print(f'Took {end-start} seconds')

if __name__ == '__main__':
    main()

Это будет обрабатывать 4 задачи одновременно, а также с количеством задач10, это займет около 4 + 4 + 4 = 12 секунд

Первый 4 секунды для первых 4 задач

Секунды 4 секунды для секунд 4 задач

И финал 4 секунд для последних 2 задач Осталось

Вывод:

$ python run.py
Took 12.005989074707031 seconds
1 голос
/ 20 сентября 2019

Я считаю, что это должно работать:

import subprocess
import time


def check_for_done(l):
    for i, p in enumerate(l):
        if p.poll() is not None:
            return True, i
    return False, False


processes = list()
N = 5
queue = list()
for process in queue:
    p = subprocess.Popen(process)
    processes.append(p)
    if len(processes) == N:
        wait = True
        while wait:
            done, num = check_for_done(processes)

            if done:
                processes.pop(num)
                wait = False
            else:
                time.sleep(0.5) # set this so the CPU does not go crazy

Итак, у вас есть список активных процессов, и функция check_for_done проходит по нему, подпроцесс возвращает None, если он не завершен, и возвращает код возврата, еслиэто.Поэтому, когда что-то возвращается, это должно быть сделано (не зная, было ли это успешным или нет).Затем вы удаляете этот процесс из списка, позволяя циклу добавить еще один.

...