![](/img/trans.png)
[英]split numbers in and store them in different files using unix shell script
[英]How to split files up and process them in parallel and then stitch them back? unix
我有一个文本文件infile.txt
如下:
abc what's the foo bar.
foobar hello world, hhaha cluster spatio something something.
xyz trying to do this in parallel
kmeans you're mean, who's mean?
文件中的每一行都将通过此perl命令处理到out.txt中
`cat infile.txt | perl dosomething > out.txt`
想象一下,如果文本文件是100,000,000行。 我想并行化bash命令,所以我尝试了这样的事情:
$ mkdir splitfiles
$ mkdir splitfiles_processed
$ cd splitfiles
$ split -n3 ../infile.txt
$ for i in $(ls); do "cat $i | perl dosomething > ../splitfiles_processed/$i &"; done
$ wait
$ cd ../splitfiles_processed
$ cat * > ../infile_processed.txt
但是,有一种不那么冗长的方式来做同样的事情吗?
@Ulfalizer的答案为您提供了解决方案的良好提示,但缺乏细节。
你可以使用GNU parallel (Debian上的apt-get install parallel
)
因此,使用以下命令可以解决您的问题:
parallel -a infile.txt -l 1000 -j10 -k --spreadstdin perl dosomething > result.txt
这是论证的意义
-a: read input from file instead of stdin
-l 1000: send 1000 lines blocks to command
-j 10: launch 10 jobs in parallel
-k: keep sequence of output
--spreadstdin: sends the above 1000 line block to the stdin of the command
我自己从未尝试过,但GNU parallel可能值得一试。
以下是手册页( parallel(1)
)的摘录,与您目前正在进行的操作类似。 它也可以用其他方式分割输入。
EXAMPLE: Processing a big file using more cores To process a big file or some output you can use --pipe to split up the data into blocks and pipe the blocks into the processing program. If the program is gzip -9 you can do: cat bigfile | parallel --pipe --recend '' -k gzip -9 >bigfile.gz This will split bigfile into blocks of 1 MB and pass that to gzip -9 in parallel. One gzip will be run per CPU core. The output of gzip -9 will be kept in order and saved to bigfile.gz
这是否值得取决于您的处理CPU密集程度。 对于简单的脚本,您将花费大部分时间将数据移入和移出磁盘,并行化并不会让您受到太多影响。
您可以找到由GNU并行笔者部分介绍影片在这里 。
假设您的限制因素不是您的磁盘,您可以使用fork()
并特别是Parallel::ForkManager
在perl中执行此Parallel::ForkManager
:
#!/usr/bin/perl
use strict;
use warnings;
use Parallel::ForkManager;
my $max_forks = 8; #2x procs is usually optimal
sub process_line {
#do something with this line
}
my $fork_manager = Parallel::ForkManager -> new ( $max_forks );
open ( my $input, '<', 'infile.txt' ) or die $!;
while ( my $line = <$input> ) {
$fork_manager -> start and next;
process_line ( $line );
$fork_manager -> finish;
}
close ( $input );
$fork_manager -> wait_all_children();
做这样的事情的缺点是合并你的输出。 每个并行任务不一定按照它开始的顺序完成,因此您有关于序列化结果的各种潜在问题。
您可以使用像flock
这样的东西解决这些问题,但是您需要小心,因为太多的锁定操作可能会首先夺走您的并行优势。 (因此我的第一个声明 - 如果你的限制因素是磁盘IO,那么并行性无论如何都无济于事)。
但是有各种可能的解决方案 - 在perl docs中写了很多章节: perlipc - 但请记住,你也可以用Parallel::ForkManager
检索数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.