并行执行Unix命令?

Parallel execution of Unix command?

我写了一个 shell 程序,它使用 csplit 自动将文件分成 4 个部分,然后是四个 shell 程序,它使用 nohup 在后台执行相同的命令和一个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+=} END {print s}'
10000000

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

当我为 2GB 文件(约 1000 万)条记录尝试此操作时,它花费了 20 多分钟。

这个命令只能在多核系统上使用吗(我目前使用的是单核系统)

nproc --all
1

简而言之,是的。您将需要机器上的更多物理内核才能从并行中获益。只是为了了解你的任务;以下是您打算执行的操作

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 代表处理器数量。

更新 为什么要在 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 进行高速数据访问。

--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+=} 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+=} 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+=} 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+=} END {print s}'
1888888898

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

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

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

但是,您计算机的时间告诉我,这其中有一些非常不对劲的地方。我会建议您在另一台计算机上测试您的程序。