通过将命令行工具包装在带有gnu信号量的bash脚本中来并行化

时间:2016-09-30 15:59:08

标签: bash semaphore gnu-parallel

我必须在一个包含50000个文件的相当大的基准测试中对命令行工具进行评估。
不幸的是,该工具没有并行化,并且在此基准上按顺序运行它需要很长时间我阅读了一些关于gnu parallel(或gnu semaphore)的帖子,但我找不到一个很好的例子来说明如何组合由gnu信号量产生的多个后台进程的结果。

展开的工具需要一个文件作为输入参数,我必须找到一种方法来收集通过多次并行运行工具而产生的所有结果。
此外,我不想在发生碰撞时失去任何结果。
每当脚本被取消时,它都不应该重新处理之前已经处理过的任何文件。

为确保后台进程worker有足够的工作要做,下面的脚本会立即将多个文件传递给worker
bash脚本适用于我的用例

如果有人有类似的问题,我想与你分享脚本。
通过修改worker函数和修改变量{{1},可以使脚本适应另一个用例}和$JOBS

如果你能提供一些关于如何提高脚本效率的反馈,我将非常高兴。

非常感谢,   儒略

$WPSIZE

1 个答案:

答案 0 :(得分:2)

并行追加到FIFO通常是一个坏主意:你真的需要知道很多关于这个版本的OS如何缓冲FIFO以确保安全。这个例子说明了原因:

#!/bin/bash

size=3000

myfifo=/tmp/myfifo$$
mkfifo $myfifo

printone() {
  a=$( perl -e 'print ((shift)x'$size')' $1 )
  # Print a single string
  echo $a >> $myfifo
}
printone a &
printone b &
printone c &
printone d &

# Wait a little to get the printones started
sleep .1

cat $myfifo | perl -ne 'for(split//,$_){
  if($_ eq $l) {
    $c++
  } else {
    /\n/ and next;
    print $l,1+$c," "; $l=$_; $c=0;
  }
}'
echo

使用size=10,您将始终获得:

1 a10 b10 c10 

这意味着从FIFO读取10 a后跟10 b,然后是10 c。即没有混合。

但是将其更改为size=100000并获得类似的内容:

1 d65536 b65536 c100000 d34256 b34256 a100000 d208 

65K读,然后65K b,然后是100k c,然后是34K d,32K b,然后是100k a,最后208 d。即四个产出混合在一起。非常不好。

出于这个原因,我建议不要同时追加同一个FIFO:存在竞争条件的风险,通常可以避免。

在你的情况下,似乎你只想对每个50000文件# do something ...,这很简单:

do_something() {
  # do something ...
  echo do something to $1
  echo result of $1 is foo
}
export -f do_something
find . -name "*.txt" | parallel do_something > results

GNU Parallel帮助您确保stdout和stderr不会混合每个作业。

为避免在发生崩溃/取消时进行重新处理,请使用--joblog--resume