3
#!/usr/bin/perl
use strict;
use warnings;
use Tie::File;
use Data::Dumper;
use Benchmark;

my $t0 = Benchmark->new;

# all files in the current folder with $ext will be input.
# Default $ext is "pileup"
# if entered, second user entered input will be set to $ext
my $ext = "pileup";
if(exists $ARGV[1]) {
    $ext = $ARGV[1];
}

# open current directory & store filenames with $ext into @pileupfiles
opendir (DIR, ".");
my @pileupfiles = grep {-f && /\.$ext$/} readdir DIR;

my $dnasegment;
my $pos;
my $total;
my $g_total;
my @index; #hold current index for each tied file
my @totalfiles; #hold total files in each sub-index

# $filenum is iterator to cycle through all pileup files whose names are stored   in pileupfiles
my $filenum = 0;
# @tied is an array holding all arrays of tied files
my @tied;
# array of the current line number for each @file, 
my @linenum;
# tie each file to an array that is an element of the @tied array
while($filenum < scalar @pileupfiles) {
    my @file;
    tie @file, 'Tie::File', $pileupfiles[$filenum], recsep => "\n"  or die;
    push(@tied, [@file]);
    # set each line's value of $linenum to 0
    push(@linenum, 0);
    $filenum++;
}

# open user list of dnasegments
open(LIST, $ARGV[0]);
# open file for output
open(OUT, ">>tempfile.tab");

while(<LIST>) {
    $dnasegment = $_;
    chomp $dnasegment;

    my $exit = 0;
    $pos = 1;
    my %flag;

    while(scalar(keys %flag) < scalar @tied) {
        $total = 0;
        $filenum = 0;
        while($filenum < scalar @tied) {
            if(exists $tied[$filenum][$linenum[$filenum]]) {
                my @line = split(/\t/, $tied[$filenum][$linenum[$filenum]]);
                #print $line[0], "\t", $line[1], "\t", $line[3], "\n\n";
                if($line[0] eq $dnasegment) {
                    if($line[1] == $pos) {
                        $total += $line[3];
                        $linenum[$filenum]++;
                        $g_total += $line[3];
                        print OUT "$dnasegment\t$filenum\t$pos\t$line[3]\n";
                    }
                } else {
                    $flag{$filenum} = 1;
                }
            } else {
                #print $flag, "\n";
                $flag{$filenum} = 1;
            }
            $filenum++;
        }
        if($total > 0) {
            print OUT "$dnasegment\t$total\n";
        }
        $pos++;
    }
}

close (LIST);
close(OUT);

my $t1 = Benchmark->new;
my $td = timediff($t1, $t0);
print timestr($td), "\n";

上記のコードは、ディレクトリ内のデフォルトまたはユーザーが入力したファイル拡張子を持つすべてのファイルを取得し、特定のエントリ (入力ファイルの列 1列 1 は、コマンド ラインで指定されたファイルに含まれる名前と一致します)。プログラムで使用されるファイルのレイアウトは次のとおりです。 ファイル 1:

    Gm02    11896804    G   2   .,  \'
    Gm02    11896805    G   7   ......, U`
    Gm02    11896806    G   3   .,. Sa
    Gm02    11896807    T   2   .,  U\
    Gm02    11896808    T   2   .,  ZZ
    Gm02    11896809    T   2   .,  ZZ
    Gm02    11896810    T   2   .,  B\
    Gm02    11896811    G   3   .,^!,   B]E
    Gm02    11896812    A   3   T,, BaR
    Gm02    11896822    G   3   .,, B`D

ファイル 2:

    Gm02    11896804    G   3   .,, \'
    Gm02    11896805    G   7   ......, U`
    Gm02    11896806    G   3   .,. Sa
    Gm02    11896807    T   2   .,  U\
    Gm02    11896808    T   2   .,  ZZ
    Gm02    11896809    T   2   .,  ZZ
    Gm02    11896810    T   2   .,  B\
    Gm02    11896811    G   3   .,^!,   B]E
    Gm02    11896812    A   3   T,, BaR
    Gm02    11896813    G   3   .,, B`D

ファイル 3:

    Gm02    11896804    G   3   .,, \'
    Gm02    11896805    G   7   ......, U`
    Gm02    11896806    G   3   .,. Sa
    Gm02    11896807    T   2   .,  U\
    Gm02    11896808    T   2   .,  ZZ
    Gm02    11896809    T   2   .,  ZZ
    Gm02    11896810    T   2   .,  B\
    Gm02    11896811    G   3   .,^!,   B]E
    Gm02    11896812    A   3   T,, BaR
    Gm02    11896833    G   3   .,, B`D

この場合、プログラムに渡される唯一のコマンド ライン引数は、内容が "Gm02" のテキスト ファイルになります。

ハッシュは、すでに処理された場所を追跡するために使用されます。上記の例のファイルでは、位置 11896804 で最初の値が検出される前に、3 つのファイルすべてがチェックされ、位置 1 から 11896803 までカウントされます。

私の質問はパフォーマンスに関係しています。Tie::File を使用することを決定したのは、すべてのファイルがメモリに読み込まれるわけではないため、パフォーマンスが向上すると理解していたからです。プログラムによって処理される実際のデータは、数十万行の長さに数十ファイルを掛けたものです。この時点で、サンプル ファイル 1 のみと 3 つのサンプル ファイルすべての実行にかかった時間は、それぞれ 42 ウォールクロック秒 (41.96 usr + 0.00 sys = 41.96 CPU) と 110 ウォールクロック秒 (109.76 usr + 0.00 sys = 109.76 CPU) です。このプログラムの実行速度が非常に遅い理由や、速度を上げる方法についてのアドバイスをいただければ幸いです。

edit 10:17PM EST: プログラムからの出力は次のとおりです。

Gm02    0   11896804    2
Gm02    1   11896804    3
Gm02    2   11896804    3
Gm02    8
Gm02    0   11896805    7
Gm02    1   11896805    7
Gm02    2   11896805    7
Gm02    21
Gm02    0   11896806    3
Gm02    1   11896806    3
Gm02    2   11896806    3
Gm02    9
Gm02    0   11896807    2
Gm02    1   11896807    2
Gm02    2   11896807    2
Gm02    6
Gm02    0   11896808    2
Gm02    1   11896808    2
Gm02    2   11896808    2
Gm02    6
Gm02    0   11896809    2
Gm02    1   11896809    2
Gm02    2   11896809    2
Gm02    6
Gm02    0   11896810    2
Gm02    1   11896810    2
Gm02    2   11896810    2
Gm02    6
Gm02    0   11896811    3
Gm02    1   11896811    3
Gm02    2   11896811    3
Gm02    9
Gm02    0   11896812    3
Gm02    1   11896812    3
Gm02    2   11896812    3
Gm02    9
Gm02    1   11896813    3
Gm02    3
Gm02    0   11896822    3
Gm02    3
Gm02    2   11896833    3
Gm02    3
Gm02    0   11896804    2
Gm02    1   11896804    3
Gm02    5
Gm02    0   11896805    7
Gm02    1   11896805    7
Gm02    14
Gm02    0   11896806    3
Gm02    1   11896806    3
Gm02    6
Gm02    0   11896807    2
Gm02    1   11896807    2
Gm02    4
Gm02    0   11896808    2
Gm02    1   11896808    2
Gm02    4
Gm02    0   11896809    2
Gm02    1   11896809    2
Gm02    4
Gm02    0   11896810    2
Gm02    1   11896810    2
Gm02    4
Gm02    0   11896811    3
Gm02    1   11896811    3
Gm02    6
Gm02    0   11896812    3
Gm02    1   11896812    3
Gm02    6
Gm02    1   11896813    3
Gm02    3
Gm02    0   11896822    3
Gm02    3
Gm02    0   11896804    2
Gm02    2
Gm02    0   11896805    7
Gm02    7
Gm02    0   11896806    3
Gm02    3
Gm02    0   11896807    2
Gm02    2
Gm02    0   11896808    2
Gm02    2
Gm02    0   11896809    2
Gm02    2
Gm02    0   11896810    2
Gm02    2
Gm02    0   11896811    3
Gm02    3
Gm02    0   11896812    3
Gm02    3
Gm02    0   11896822    3
Gm02    3
4

2 に答える 2

6

次のコード行の外にいないことを除いて、「Tie::Fileを使用しているため」と言います。

my @file;
tie @file, 'Tie::File', $pileupfiles[$filenum], recsep => "\n"  or die;
push(@tied, [@file]);

あなたはそれを次のように書いた方がよいでしょう

open(my $fh, '<', $pileupfiles[$filenum]) or die $!;
push(@tied, [ <$fh> ]);

おそらくあなたは意味しました

tie my @file, 'Tie::File', $pileupfiles[$filenum], recsep => "\n"  or die;
push(@tied, \@file);

その後、元の答えに戻ります。Tie :: Fileは、場合によっては開発時間を短縮する可能性がありますが、これが最速のソリューションになるとは限らず、必要なメモリをはるかに多く使用する可能性があります。


ちなみに、exist配列要素では意味がありません。

if (exists $tied[$filenum][$linenum[$filenum]])

悪いやり方です

if (defined $tied[$filenum][$linenum[$filenum]])

また

if ($linenum[$filenum] < @{ $tied[$filenum] })
于 2013-02-11T21:23:10.887 に答える
0

出力がどのように見えるか疑問に思います。このようなものでしょうか(上記のサンプルファイルを考えると)?

$VAR1 = {
          'Gm02;11896804' => 8,
          'Gm02;11896805' => 21,
          'Gm02;11896806' => 9,
          'Gm02;11896807' => 6,
          'Gm02;11896808' => 6,
          'Gm02;11896809' => 6,
          'Gm02;11896810' => 6,
          'Gm02;11896811' => 9,
          'Gm02;11896812' => 9,
          'Gm02;11896813' => 3,
          'Gm02;11896822' => 3,
          'Gm02;11896833' => 3
        };
于 2013-02-12T02:45:02.370 に答える