并行 shell 循环

并行 shell 循环

我想处理许多文件,而且由于我这里有一堆核心,所以我想并行执行:

for i in *.myfiles; do do_something $i `derived_params $i` other_params; done

我知道 Makefile解决方案但是我的命令需要 shell 通配列表中的参数。我发现:

> function pwait() {
>     while [ $(jobs -p | wc -l) -ge $1 ]; do
>         sleep 1
>     done
> }
>

要使用它,只需在作业和 pwait 调用之后放置 &,参数给出并行进程的数量:

> for i in *; do
>     do_something $i &
>     pwait 10
> done

但这种方法效果不太好,例如我尝试用 for 循环转换许多文件但出现错误并且未完成任何工作。

我不敢相信这还没完成,因为 zsh 邮件列表上的讨论已经很久了。那么你知道更好的方法吗?

答案1

一个 makefile很好地解决了您的问题。您可以在 shell 中编写此并行执行程序,但正如您所注意到的,这很难。并行实现 make 不仅会负责启动作业并检测其终止,还会处理负载平衡,这很棘手。

通配符的要求并不是一个障碍:有支持它的 make 实现。GNU make 具有通配符扩展,例如$(wildcard *.c)和 shell 访问,例如$(shell mycommand)(有关更多信息,请参阅 GNU make 手册中的函数)。它是makeLinux 上的默认设置,在大多数其他系统上都可用。这是一个 Makefile 框架,您可以根据需要进行调整:

来源 = $(通配符 *.src)

全部:$(来源:.src=.tgt)

%.tgt: %.src
    do_something $< $$(derived_pa​​rams $<) >$@

运行类似并行make -j4执行四个作业的程序,或者make -j -l3保持平均负载在 3 左右。

答案2

我不确定你的派生参数是什么样的。但使用 GNU Parallel http://www.gnu.org/software/parallel/,你可以这样做,每个 CPU 核心运行一个作业:

find . | parallel -j+0 'a={}; name=${a##*/}; upper=$(echo "$name" | tr "[:lower:]" "[:upper:]");
   echo "$name - $upper"'

如果您想要得到的只是改变 .extension,则 {.} 可能会很方便:

parallel -j+0 lame {} -o {.}.mp3 ::: *.wav

观看 GNU Parallel 的介绍视频http://www.youtube.com/watch?v=OpaiGYxkSuQ

答案3

使用 shell 的wait命令对您不起作用吗?

for i in *
do
    do_something $i &
done
wait

您的循环执行一项作业,然后等待它,然后执行下一项作业。如果上述方法对您不起作用,那么如果您pwait在之后移动,您的循环可能会更好地工作done

答案4

我尝试了一些答案。它们使脚本比需要的更复杂一些。理想情况下,使用parallelxargs会更好,但是如果 for 循环中的操作很复杂,则创建大而长的行文件以提供给并行可能会有问题。相反,我们可以使用源,如下所示

# Create a test file 
$ cat test.txt
task_test 1
task_test 2

# Create a shell source file 
$ cat task.sh
task_test()
{
    echo $1
}

# use the source under bash -c 
$ cat test.txt | xargs -n1 -I{} bash -c 'source task.sh; {}'
1
2

因此,对于你的问题解决方案如下

for i in *.myfiles; echo " do_something $i `derived_params $i` other_params
" >> commands.txt ; done

将做某事定义为do_something.sh

do_something(){
process $1
echo $2 
whatever $3 

}

xarg或执行gnu parallel

   cat commands.txt | xargs -n1 -I{} -P8 bash -c 'source do_something.sh; {}'

我假设 for 的迭代函数独立性是隐含的。

相关内容