使用并行处理唯一输入文件到唯一输出文件

J J*_*nes 18 scripting parallelism gnu-parallel

我有一个 shell 脚本问题,我得到了一个充满输入文件的目录(每个文件包含许多输入行),我需要单独处理它们,将它们的每个输出重定向到一个唯一的文件(也就是 file_1.input 需要在 file_1.output 中捕获,依此类推)。

并行前,我只会遍历目录中的每个文件并执行我的命令,同时执行某种计时器/计数技术以免使处理器不堪重负(假设每个进程都有一个恒定的运行时间)。但是,我知道情况并非总是如此,因此使用类似“并行”的解决方案似乎是无需编写自定义代码即可获得 shell 脚本多线程的最佳方法。

虽然我已经想到了一些方法来并行处理这些文件中的每一个(并允许我有效地管理我的内核),但它们似乎都很笨拙。我有一个我认为非常简单的用例,所以我希望尽可能保持干净(并且并行示例中的任何内容似乎都不是我的问题。

任何帮助,将不胜感激!

输入目录示例:

> ls -l input_files/
total 13355
location1.txt
location2.txt
location3.txt
location4.txt
location5.txt
Run Code Online (Sandbox Code Playgroud)

脚本:

> cat proces_script.sh
#!/bin/sh

customScript -c 33 -I -file [inputFile] -a -v 55 > [outputFile]
Run Code Online (Sandbox Code Playgroud)

更新:阅读下面 Ole 的回答后,我能够为我自己的并行实现将缺失的部分放在一起。虽然他的回答很好,但这是我的补充研究和笔记:

我没有运行我的整个过程,而是从概念证明命令开始,以在我的环境中证明他的解决方案。查看我的两个不同的实现(和注释):

find /home/me/input_files -type f -name *.txt | parallel cat /home/me/input_files/{} '>' /home/me/output_files/{.}.out
Run Code Online (Sandbox Code Playgroud)

使用 find(而不是 ls,会导致问题)在我的输入文件目录中查找所有适用的文件,然后将它们的内容重定向到单独的目录和文件。我上面的问题是读取和重定向(实际脚本很简单),所以用 cat 替换脚本是一个很好的概念证明。

parallel cat '>' /home/me/output_files/{.}.out :::  /home/me/input_files/*
Run Code Online (Sandbox Code Playgroud)

第二个解决方案使用并行的输入变量范式来读取文件,但是对于新手来说,这更加令人困惑。对我来说,使用 find a 和 pipe 很好地满足了我的需求。

Ole*_*nge 27

GNU Parallel 专为此类任务而设计:

parallel customScript -c 33 -I -file {} -a -v 55 '>' {.}.output ::: *.input
Run Code Online (Sandbox Code Playgroud)

或者:

ls | parallel customScript -c 33 -I -file {} -a -v 55 '>' {.}.output
Run Code Online (Sandbox Code Playgroud)

它将为每个 CPU 内核运行一个作业。

您可以简单地通过以下方式安装 GNU Parallel:

wget https://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
Run Code Online (Sandbox Code Playgroud)

观看 GNU Parallel 的介绍视频以了解更多信息:https : //www.youtube.com/playlist?list=PL284C9FF2488BC6D1


Sha*_*off 5

执行此操作的标准方法是设置一个队列并生成任意数量的知道如何从队列中提取某些内容并对其进行处理的工作人员。您可以使用 fifo(又名命名管道)在这些进程之间进行通信。

下面是一个简单的例子来演示这个概念。

一个简单的队列脚本:

#!/bin/sh
mkfifo /tmp/location-queue
for i in inputfiles/*; do
  echo $i > /tmp/location-queue
done
rm /tmp/location-queue
Run Code Online (Sandbox Code Playgroud)

还有一个工人:

#!/bin/sh
while read file < /tmp/location-queue; do
  process_file "$file"
done
Run Code Online (Sandbox Code Playgroud)

process_file 可以在您的工人中的某个地方定义,它可以做您需要做的任何事情。

一旦你有了这两个部分,你就可以有一个简单的监视器来启动队列进程和任意数量的工作进程。

监控脚本:

#!/bin/sh
queue.sh &
num_workers="$1"
i=0
while [ $i < $num_workers ]; do
  worker.sh &
  echo $! >> /tmp/worker.pids
  i=$((i+1))
done
monitor_workers
Run Code Online (Sandbox Code Playgroud)

你有它。如果你真的这样做了,最好在监视器中设置先进先出,并将路径传递给队列和工作人员,这样它们就不会耦合并且不会被固定到先进先出的特定位置。我在答案中专门设置了这种方式,因此很明显您在阅读时使用的是什么。


小智 5

另一个例子:

ls *.txt | parallel 'sort {} > {.}.sorted.txt'
Run Code Online (Sandbox Code Playgroud)

我发现其他示例不必要地复杂,而在大多数情况下,上述示例可能是您一直在寻找的。