Скрипт для запуска нескольких экземпляров программы параллельно с аргументами - PullRequest
0 голосов
/ 05 ноября 2018

Я хочу иметь возможность запускать один сценарий (например, сценарий python или любой другой, который имеет наибольшее значение для этих вещей), который будет делать что-то эквивалентное чему-то вроде:

$ program -i input -k 0.1 -m 0.01 &
$ program -i input -k 0.2 -m 0.22 &
$ program -i input -k 0.3 -m 3.03 &

Я бы хотел установить в скрипте любые параметры, которые мне нужны, и просто набрать «python script.py», чтобы он запускал сколько угодно экземпляров программы, все параллельно, в фоновом режиме. Я видел, как люди рекомендуют subprocess.Popen(), но я не знаю, как настроить его для параллельного запуска нескольких заданий. Как мне это сделать?

Я подумал составить список команд и выполнить итерации по ним, но 1) я думаю, что нужно дождаться завершения первого задания, прежде чем запускать второе задание в очереди, и 2) оно кажется неэффективным.

Кроме того, если написание этого скрипта на python не имеет смысла, дайте мне знать, что будет лучшей альтернативой; Я никогда не делал этого раньше и не знаю, что делаю.

1 Ответ

0 голосов
/ 06 ноября 2018

Простое решение Python с использованием модуля multiprocessing может выглядеть так:

import os
import multiprocessing

def run_command(cmd):
    """ execute cmd via the shell. """
    print("starting `{}` ...".format(cmd))
    os.system(cmd)
    print("end `{}`".format(cmd))

def run_commands(commands, n_parallel):
    """ run commands (up to n_parallel in parallel). """
    worker = multiprocessing.Pool(n_parallel)
    worker.map(run_command, commands)

if __name__ == "__main__":
    run_commands([
        "program -i input -k 0.1 -m 0.01",
        "program -i input -k 0.2 -m 0.22",
        "program -i input -k 0.3 -m 3.03",
    ], n_parallel=2)

Центральным элементом является map() метод multiprocessing.Pool. Эта функция принимает список входных значений (в нашем случае, команд оболочки) и передает их в другую функцию, каждая в своем собственном процессе, вплоть до размера параллельных процессов пула.

У этого простого скрипта есть один недостаток: вывод команд оболочки, работающих параллельно, будет перепутан. Этого можно избежать путем захвата и возврата вывода команд в run_command(), например. используя subprocess.check_output() вместо os.system():

import subprocess

def run_command(cmd):
    try:
        output = subprocess.check_output(cmd, shell=True)
    except subprocess.CalledProcessError:
        output = "ERROR in {}".format(cmd)
    return output

multiprocessing.Pool.map() соберет и вернет эти выходные данные в виде списка, который мы можем повторно объединить с командами, чтобы run_commands() вернул список пар (команда, выход):

def run_commands(commands, n_parallel=2):
    worker = multiprocessing.Pool(n_parallel)
    for cmd, output in zip(commands, worker.map(run_command, commands)):
        print("{}: {}".format(cmd, output))

Теперь, поскольку мы выводим вывод после , когда все параллельные процессы завершены, он не будет перепутан.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...