并行执行Unix命令?

时间:2017-01-29 13:37:55

标签: unix gnu-parallel

我编写了一个shell程序,它使用csplit自动将文件分成4个部分,然后使用nohup在后​​台执行相同命令的4个shell程序,一个while循环将查找这些文件的完成情况四个进程,最后是cat output1.txt .... output4.txt> finaloutput.txt

但后来我开始了解这个命令parallel,我尝试使用大文件,但看起来它没有按预期工作。此文件是以下命令的输出 -

for i in $(seq 1 1000000);do cat /etc/passwd >> data.txt1;done

time wc -l data.txt1
10000000 data.txt1

real    0m0.507s
user    0m0.080s
sys     0m0.424s

并行

time cat data.txt1 | parallel  --pipe wc -l | awk '{s+=$1} END {print s}'
10000000

real    0m41.984s
user    0m1.122s
sys     0m36.251s

当我尝试使用2GB文件(~1000万)记录时,花了20多分钟。

此命令是否仅适用于多核系统(我目前使用的是单核系统)

nproc --all
1

2 个答案:

答案 0 :(得分:3)

--pipe效率低下(虽然不是你所测量的规模 - 你系统上的某些东西是非常错误的)。它可以以1 GB / s(总计)的顺序提供。

相反,

--pipepart非常高效。如果您的磁盘足够快,它可以以每核1 GB / s的速度提供。这应该是处理data.txt1的最有效方式。它会将data.txt1拆分为每个cpu核心一个块,并将这些块提供给每个核心上运行的wc -l

parallel  --block -1 --pipepart -a data.txt1 wc -l

您需要版本20161222或更高版本才能使block -1正常工作。

这些是来自我的旧双核笔记本电脑的时间。 seq 200000000生成1.8 GB的数据。

$ time seq 200000000 | LANG=C wc -c
1888888898

real    0m7.072s
user    0m3.612s
sys     0m2.444s

$ time seq 200000000 | parallel --pipe LANG=C wc -c | awk '{s+=$1} END {print s}'
1888888898

real    1m28.101s
user    0m25.892s
sys     0m40.672s

这里的时间主要是由于GNU Parallel为每个1 MB块生成一个新的wc -c。增加块大小会使其更快:

$ time seq 200000000 | parallel --block 10m --pipe LANG=C wc -c | awk '{s+=$1} END {print s}'
1888888898

real    0m26.269s
user    0m8.988s
sys     0m11.920s

$ time seq 200000000 | parallel --block 30m --pipe LANG=C wc -c | awk '{s+=$1} END {print s}'
1888888898

real    0m21.628s
user    0m7.636s
sys     0m9.516s

如上所述--pipepart如果文件中包含数据则要快得多:

$ seq 200000000 > data.txt1
$ time parallel --block -1 --pipepart -a data.txt1 LANG=C wc -c | awk '{s+=$1} END {print s}'
1888888898

real    0m2.242s
user    0m0.424s
sys     0m2.880s

因此,在我的旧笔记本电脑上,我可以在2.2秒内处理1.8 GB。

如果您只有一个核心并且您的工作依赖于CPU,那么并行化将无助于您。如果大部分时间都花在等待(例如,等待网络),那么在单个核心机器上并行化是有意义的。

但是,计算机的时间告诉我这是非常错误的。我建议你在另一台电脑上测试你的程序。

答案 1 :(得分:0)

简而言之是..您需要在机器上使用更多物理内核才能从并行中获益。只是为了理解你的任务;以下是你打算做的事情

file1 is a 10,000,000 line file

split into 4 files > 
file1.1  > processing > output1
file1.2  > processing > output2
file1.3  > processing > output3
file1.4  > processing > output4

>> cat output* > output 
________________________________

并且您希望并行化中间部分并同时在4个核心(希望是4个核心)上运行它。我对么?我认为你可以用更好的方式使用GNU parallel为其中一个文件编写代码并使用该命令(psuedocode warning)

parallel --jobs 4 "processing code on the file segments with sequence variable {}"  ::: 1 2 3 4 

其中-j表示处理器数量。

UPDATE 为什么要在file1.1 1.2 1.3和1.4中尝试并行执行顺序执行命令?让它成为你编码的常规顺序处理

parallel 'for i in $(seq 1 250000);do cat file1.{} >> output{}.txt;done' ::: 1 2 3 4 

以上代码将在4核上并行运行csplit的4个分段文件

for i in $(seq 1 250000);do cat file1.1 >> output1.txt;done
for i in $(seq 1 250000);do cat file1.2 >> output2.txt;done
for i in $(seq 1 250000);do cat file1.3 >> output3.txt;done
for i in $(seq 1 250000);do cat file1.4 >> output4.txt;done

我很确定 - Ole上面提到的--diskpart是更好的方法;鉴于您可以从HDD进行高速数据访问。