以下程序运行正常,但大数据需要无限时间。
INPUT.txt 。实际上,我有多达1000行,每行有1到100个元素。
10
6
9
7
9 11
3 4
1 9
5 12
1 11
5 11
9 12
10 5 8
7 4 1
and so on...
last: 1 2 3 4 5 6 7 . . .any number of elements (100 in my case).
matrix.txt (TAB DELIMIITED)
1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1
1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 0 1 0 0 1 1
1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0
1 0 1 1 1 1 0 1 1 1 1 0 1 1 0 1 1 0 1 1 1 1 0 1 0 1 1 1
1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1
1 0 1 1 1 1 0 1 1 1 1 0 1 1 0 0 1 0 1 1 1 1 1 1 0 0 1 1
1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 1 1 1 1 0
and so on....upto 25000 lines
output.txt的
这些是在矩阵中的总和,它位于从INPUT.txt的每一行取得的索引位置。
实际总和可能与此假设样本输出不同。
1 1 1 1 1 0 1 1 1 2 2 2 2 2 . . .columns upto number of lines in input.txt
1 1 1 1 1 1 1 1 1 2 2 2 2 2
1 0 0 1 1 1 1 1 1 2 2 2 2 2
1 1 1 0 1 0 0 1 1 2 2 2 2 2
1 1 1 1 1 1 1 1 0 2 2 2 2 2
1 1 1 0 1 0 1 1 1 1 2 2 2 2
1 1 1 1 1 0 1 1 1 2 2 2 2 2
1 1 1 1 1 0 0 1 1 1 2 2 2 2
0 1 1 1 1 1 1 1 0 2 2 2 2 2
代码:查看代码,它将帮助您了解正在发生的事情。
use List::Util 'sum';
my @indexes = do {
open my $fh, '<', "INPUT.txt";
map { [map {$_ - 1} split ' '] } <$fh>
};
open my $infh, '<', "matrix.txt";
open OUT, '>', "output.txt";
while (<$infh>) {
my @vals = split ' ';
print OUT join(' ', map {sum(@vals[@$_])} @indexes), "\n";
}
close OUT;
还有其他方法可以在较短的时间内完成此任务。
文件可用性:
输入:https://www.dropbox.com/s/48ikhnfs7gzk8vm/input.txt?dl=0
MATRIX:https://www.dropbox.com/s/ebxi608eday9z1e/matrix.txt?dl=0
答案 0 :(得分:3)
要看/尝试的一件事是cpan上的数学和矩阵导向模块。其中一些使用本机代码(是基于c的perl扩展),其中应该更快。这是他们的(过时的)入门书 -
答案 1 :(得分:2)
我制作了一个PDL版本,利用了这个事实,你实际上是在用选择向量进行矩阵乘法。此版本假设矩阵中始终包含100个元素。如果不是这样,你必须相应地改变零调用。
输入尺寸(1 000 x 100)(25 000 x 100)的速度大约是其两倍。将整个矩阵读入内存,然后在同一运行时处理结果,但如果启用并行性可能会更快。如果您想知道大致的运行时间大小是多少,优化的c版本运行速度比原来大约快4倍(原始版本的8倍)。所有时间都与我的机器有关,但我希望在大多数计算机上都有类似的比例。我也没有声称我的PDL是最佳的,因为我以此为借口来学习它。
use strict;
use warnings;
use PDL;
my $indexes = PDL::long(do {
open(my $fh, '<', 'INPUT.txt') or die;
# The first map is if you allow duplicates in the index list (i.e. 2 2 is a valid row)
# map { my $p = zeroes(100); $p->slice($_)++ foreach (map {$_ - 1} split /\t/); $p } <$fh>
map { zeroes(100)->dice([map {$_ - 1} split /\t/])++ } <$fh>
})->xchg(0, 1);
open(my $input, '<', 'matrix.txt') or die;
open(my $output, '>', 'output.txt') or die;
while(<$input>) {
my $vals = PDL::long(split(/\t/));
print $output join("\t", ($vals x $indexes)->list) . "\n";
}
答案 2 :(得分:0)
您是否可以更好地了解哪些&#39;&#39;是你的表现吗?
我问的原因 - 这是一种神圣的三位一体的性能瓶颈:
您经常可以通过创建查找表来获得CPU效率。
map等操作是我开始关注的事情 - 像map / sort / grep这样的东西非常强大,但有可能使用不太理想的算法。
如果你受CPU限制,你可以尝试使用多线程或分叉来增加CPU访问。从表面上看,看起来就像你一样,不依赖于你对'matrix.txt&#39;的处理。 (例如,每一行都是独立的)因此它可能是并行性的良好候选者。
我正在考虑使用Parallel :: ForkManager来包装while
循环。这样做的缺点是,您将对输出进行非确定性排序,这需要解决。
所以10的首发可能是:
use List::Util 'sum';
use Data::Dumper;
use Fcntl qw(:flock);
use Parallel::ForkManager;
my $mgr = Parallel::ForkManager->new(10);
my @indexes = do {
open my $fh, '<', "INPUT.txt";
map {
[ map { $_ - 1 } split ' ' ]
} <$fh>;
};
open my $infh, '<', "matrix.txt";
open my $out_fh, '>', "output.txt";
while (<$infh>) {
$mgr->start and next;
my @vals = split ' ';
my $output_line = join( ' ', map { sum( @vals[@$_] ) } @indexes ),
"\n";
{
flock( $out_fh, LOCK_EX );
print {$out_fh} $output_line;
}
}
close $out_fh;
注意 - 这会有效,但您会得到一个随机输出顺序,这几乎肯定不是您想要的。但它会同时使用10个处理器来进行“加入/映射/求和”。操作。
(当然,如果你受到IO限制,这对任何人都没有帮助)。
但是为了同步IO,我发现线程是一个很好的选择:
use warnings;
use strict;
use List::Util 'sum';
use threads;
use Thread::Queue;
my $line_q = Thread::Queue -> new();
my $output_q = Thread::Queue -> new();
my %line_output : shared;
my @indexes = do {
open my $fh, '<', "INPUT.txt";
map {
[ map { $_ - 1 } split ' ' ]
} <$fh>;
};
sub generate_output {
while ( my $item = $line_q -> dequeue() ) {
print "processing $item \n";
my ( $line_num, @vals ) = split ( ' ', $item );
$output_q -> enqueue($line_num.":". join(' ', map {sum(@vals[@$_])} @indexes ). "\n");
}
}
sub coalesce_output {
open my $out_fh, '>', "output.txt";
my $current_line = 0;
my %lines;
while ( my $item = $output_q -> dequeue ) {
my ( $line_num, $output_line ) = split ( ":", $item );
if ( $line_num = $current_line ) {
print {$out_fh} $output_line;
$current_line++;
}
else {
$lines{$line_num} = $output_line;
}
while ( defined $lines{$current_line} ) {
print {$out_fh} $lines{$current_line};
delete $lines{$current_line};
$current_line++;
}
}
}
open my $infh, '<', "matrix.txt";
my @workers;
for ( 1..10 ) {
push ( @workers, threads -> create ( \&generate_output ) );
}
threads -> create ( \&coalesce_output );
while (my $line = <$infh>) {
$line_q -> enqueue ( "$.: $line" );
}
$line_q -> end();
foreach my $thr ( @workers ) {
$thr -> join();
}
$output_q -> end();
例如。解雇10名工人&#39;并行进行求和运算,并输出一个&#39;线程以正确的顺序写入数据。
类似于:
use warnings;
use strict;
use List::Util 'sum';
use threads;
use Thread::Queue;
my $line_q = Thread::Queue->new();
my $output_q = Thread::Queue->new();
my @indexes = do {
open my $fh, '<', "INPUT.txt";
map {
[ map { $_ - 1 } split ' ' ]
} <$fh>;
};
sub generate_output {
while ( my $item = $line_q->dequeue() ) {
#print "processing $item \n";
my ( $line_num, @vals ) = split( ' ', $item );
$output_q->enqueue( $line_num . ":"
. join( ' ', map { sum( @vals[@$_] ) } @indexes )
. "\n" );
}
}
sub coalesce_output {
open my $out_fh, '>', "output.txt";
my $current_line = 1;
my %lines;
while ( my $item = $output_q->dequeue ) {
my ( $line_num, $output_line ) = split( ":", $item );
# print "Got $line_num ($current_line) $item\n";
if ( $line_num = $current_line ) {
# print "printing $current_line = $output_line\n";
print {$out_fh} $output_line;
$current_line++;
}
else {
$lines{$line_num} = $output_line;
}
while ( defined $lines{$current_line} ) {
# print "printing (while) $current_line = $lines{$current_line}\n";
print {$out_fh} $lines{$current_line};
delete $lines{$current_line};
$current_line++;
}
}
}
open my $infh, '<', "matrix.txt";
my @workers;
for ( 1 .. 40 ) {
push( @workers, threads->create( \&generate_output ) );
}
threads->create( \&coalesce_output );
while ( my $line = <$infh> ) {
$line_q->enqueue("$. $line");
}
$line_q->end();
foreach my $thr (@workers) {
$thr->join();
}
$output_q->end();
foreach my $thr ( threads -> list ) { $thr -> join(); }
制作(+更多):
1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
最后 - 它取决于你的限制因素。
运行快速而肮脏的测试
Started at 1417007048,
finished at 1417007064
Took:16s
Vs以上。
Started at 1417007118
finished at 1417007161
Took:43s
(我还没有详尽地验证两者的输出)