Общий способ параллельного запуска существующих исполняемых файлов - PullRequest
2 голосов
/ 29 марта 2012

Я пытаюсь найти решение относительно способа параллельного запуска существующих исполняемых файлов. До сих пор я придумывал создание оболочки, которая помещает указанный исполняемый файл в очередь (управляемую «сервером»). Проблема, которая у меня возникает, - когда мне нужно запустить несколько исполняемых файлов, чей вывод - это ввод другого.

Пример:

У меня есть исполняемый файл A , вывод которого - файл (изображение). У меня есть еще один исполняемый файл B , чьи входные данные представляют собой список файлов (учитывая, что он создает миниатюры из изображений A , сохраняет их в архиве и т. Д.)

Вопрос в следующем: есть ли способ заставить исполняемый файл B ожидать завершения нескольких процессов A ?

Есть ли стандартный способ сделать это? Мне интересна концепция и, если возможно, а не язык. Было бы неплохо, если бы решение было кроссплатформенным, но на данный момент у меня нет никаких решений, поэтому не стесняйтесь делиться своими идеями. Я предполагаю, что это будет как-то сделано в C / C ++, так как требует некоторого взаимодействия на низком уровне.

УПРОЩЕННЫЙ:


У меня есть несколько исполняемых файлов ( A ), работающих в фоновом режиме, и другой исполняемый файл ( B ), который использует свои выходные данные в качестве входных данных. Как я могу заблокировать выполнение B , пока все необходимые входные файлы не будут доступны.

Примечание: исполняемые файлы A постоянно работают на машине, но некоторые входные файлы периодически «собираются» с помощью B .


Спасибо за любые предложения,

Юлиан

Ответы [ 6 ]

1 голос
/ 30 марта 2012

Вам, вероятно, не нужно ничего писать:

whenjobs - это замена cron, которая не только позволяет указывать задания (потенциально повторяющиеся), но и учитывает зависимости заданий:

1 голос
/ 29 марта 2012

Если вы говорите о программе, которая делает это для вас, GNU Parallel сделает это за вас. Вы можете настроить его на работу cron или на то, что вам нужно. Мы часто запускаем его из сценариев, чтобы переписать большое количество текста (или кода) и полностью использовать все ядра машины для выполнения этой работы. Часто вы можете использовать Parallel вместе со скриптами и sed / awk, чтобы получить все, что вам действительно нужно. Однако не совсем понятно, хотите ли вы сделать это программно, поэтому, возможно, это не лучший ответ.

0 голосов
/ 30 марта 2012

Если вам нужно запустить разные исполняемые файлы в системе, я думаю, что самое чистое решение - использовать планировщик .Slurm или TORQUE должны быть хорошим выбором.

Кроме того, запрошенная вами особенность иногда упоминается как многоэтапное планирование работы.Если планировщик не поддерживается изначально, то можно легко достичь того же результата с помощью ряда заданий, которые в случае успеха отправят свое продолжение.

0 голосов
/ 30 марта 2012

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

execA=./gnuplotwrapper
execB=convert

all: figure1.png figure2.png

# convert txt files to png files using a gnuplot script "gnuplotwrapper"

%.png: %.txt
    $(execA) $^ $@

# take two figures and append them using imagemagick's "convert"

figure1.png: data1.png data2.png
    $(execB) $^ +append $@

figure2.png: data3.png data4.png
    $(execB) $^ +append $@

clean:
    rm -f *.png

будет использовать исполняемый файл A для генерации файлов изображений из файлов данных и исполняемый файл B для обработки пакетов файлов изображений.Запустив это с (скажем) make -j 4, make попытается использовать до 4 параллельных процессов для получения окончательного результата (здесь figure1.png и figure2.png).

0 голосов
/ 29 марта 2012

Я думаю, что способ сделать это - создать дерево зависимостей, где дочерние узлы зависят от выходных данных родительских узлов. Затем вы можете запускать каждый уровень своего дерева параллельно.

Например:

Выход P1 идет к P2 и P3

Выход P2 идет к P4

Выход P3 переходит на P4.

Тогда ваше дерево выглядит так:

                     P1
                    /  \
                   P2  P3
                    \  /
                     P4

Сначала нужно запустить P1, параллельно можно запустить P2 и P3, а затем выполнить P4 последним.

Кроме того, это не обязательно должен быть C ++, любой старый язык поможет, я уверен,

EDIT: Если вы не знаете, когда предыдущее задание заканчивается, чтобы запустить следующее, вы можете установить цикл, который через каждый заданный интервал времени проходит через все исполняемые файлы, которые вы хотите запустить, и проверяет, созданы ли нужные им файлы, если они они запускают его, иначе ждут следующей итерации и проверяют снова.

Общая идея (в C ++) может выглядеть примерно так:

    struct Job
    {
      bool PreconditionsSatisfied();
      void Run();
    };

    std::vector<Job> jobs;

    //Fill up with appropriate info

    while(jobs.size() != 0)
      {
        for(int i = 0; i < jobs.size(); i++)
          {
             if(jobs[i].PreconditionsSatisfied())
              {
                //start new thread and run job
                jobs.erase(jobs.begin() + i);
                i--;
              }
          }
        sleep(TIME_INTERVAL);
      }
0 голосов
/ 29 марта 2012

Обычный подход заключается в использовании примитивов синхронизации, например семафоров или барьеров.Однако это (не только) зависит от языка, но требует взаимодействия с платформой (обычно ОС).

Однако стандарт C ++ 11 развертывает стандартизированную модель потоков на уровне библиотеки.

...