并行运行现有可执行文件的通用方式

Generic way to run existing executables in parallel

本文关键字:方式 可执行文件 运行 并行      更新时间:2023-10-16

我正在尝试思考一种关于并行运行现有可执行文件的方法的解决方案。到目前为止,我所做的是制作一个包装器,将指定的可执行文件放入队列(由"服务器"管理)。我遇到的问题是,当我需要运行多个输出是另一个可执行文件输入的可执行文件时。

示例:

我有一个可执行文件A,它的输出是一个文件(一个图像)。我有另一个可执行文件B,它的输入是一个文件列表(考虑它从a的图像创建缩略图,将它们存储在档案中,等等)

问题是:有没有办法让B可执行文件等待多个a进程完成?

有标准的方法吗?我感兴趣的是这个概念,如果可能的话,而不是语言。如果解决方案是跨平台的,那就太好了,但目前我还没有任何解决方案,所以请随时分享您的想法。我认为这将以某种方式在C/C++中完成,因为它需要一些低级别的交互。

简化:


我有一些在后台运行的可执行文件(A)和另一个使用其输出作为输入的可执行程序(B)。如何阻止B的执行,直到所有需要的输入文件都可用。

注意:可执行文件A在计算机上连续运行,但一些输入文件由B定期"收集"。


感谢您的任何建议,

Iulian

如果你谈论的是一个为你做这件事的程序,GNU Parallel会为你做。您可以将其设置为在cron作业上运行,或者设置为您认为需要的任何作业。我们经常从脚本中运行它来重写大量的文本(或代码),并充分利用机器的所有核心来完成这项工作。您可以经常将Parallel与脚本和sed/awk一起使用,以完成您真正需要的任何任务。然而,我不完全清楚你是否想通过编程来实现这一点,所以这可能不是最好的答案。

您可能不需要编写任何内容:

whenjobs是一个cron替换,它不仅允许您指定作业(可能重复),还考虑到作业依赖性:

通常的方法是使用同步原语,例如信号量或屏障。然而,这并不(仅)取决于语言,而是需要与平台(通常是操作系统)进行交互。

然而,C++11标准在库级别部署了一个标准化的线程模型。

人们通常使用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个进程来构建最终结果(这里是图1.png和图2.png)。

如果您需要在系统上运行不同的可执行文件,我认为最干净的解决方案是使用调度器。Slurm或TORQUE应该是不错的选择。

此外,您要求的特定功能有时被称为多步骤作业调度。如果调度程序本身不支持,那么通过一系列作业很容易获得相同的结果,如果成功,这些作业将提交其延续。

我认为这样做的方法是创建一个依赖树,其中子节点依赖于父节点的输出。然后,您可以并行运行树的每个级别。

例如:

P1的输出进入P2和P3

P2的输出进入P4

P3的输出进入P4。

然后你的树看起来像:

                     P1
                    /  
                   P2  P3
                      /
                     P4

你必须先运行P1,P2和P3可以并行运行,然后P4最后执行。

而且它不一定是C++,任何旧的语言都会起作用,我相信

编辑:如果你不知道上一个作业何时结束,下一个作业什么时候开始,你可以设置一个循环,在每个设置的时间间隔内遍历你想要运行的所有可执行文件,并检查它们需要的文件是否已创建,如果是,则运行它,否则等待下一次迭代,然后再次检查。

一般的想法(在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);
      }
相关文章: