繁体   English   中英

我如何从csv文件读取数据并将其存储在二进制树中并在perl中写入多个文件

[英]how can i read data from csv file and store in binary tree and write multiple file in perl

我有CSV文件,数据超过100万。 我想使用binary::tree减少内存使用。

该程序的主要用途是搜索前5位并创建新文件(文件名应为前5位)以存储相同前5位的存储数据。

我的代码工作正常,但使用了大内存。

现在写我使用此代码:

my $file = "my_csv_file.csv";

open (my $data, '<', $file) or die "Could not open '$file' $!\n";

while (my $lines = <$data>) {
        my @fields = split "," , $lines unless $. == 1;

        my $first_five = substr ($fields[1],  0,  5,);

        if (-e "$first_five.csv" ) {
            open my $fh, '>>', "$first_five.csv" or die $!;
            print { $fh } $lines;

        }       else {
            open my $fh, '>>', "$first_five.csv" or die $!;
            print $fh "Title\n";
        }               
        close $fh;
}
 close $data;

我相信脚本中的性能瓶颈根本不是内存使用,而是您可以为每个记录打开和关闭文件。 如果我正确地理解了单位,那么10lakh就是1,000,000,因此很多打开和关闭。

一种解决方案是分批处理数据,尤其是如果在“前5个”中有很多重复的密钥要提取作为密钥,则尤其如此。

在第二个字段中包含100个唯一的5位数字键的合成文件中,我将您的程序与下面的程序进行了基准比较,但是合成记录为10,000,000条(文件大小的10倍)。 这些行看起来像这样:

1,9990001,----------------------------------------------------------------------------------------------------
2,9990002,----------------------------------------------------------------------------------------------------
3,9990003,----------------------------------------------------------------------------------------------------

我这样做是为了模拟输入中的大量数据。 它应该是输入文件记录数的10倍。

您的原始脚本花了2分钟以上的时间在我的计算机上处​​理此输入。 以下脚本(使用10,000条记录的批处理)耗时24秒。 速度快了5倍。

my $file = "my_csv_file.csv";

open (my $data, '<', $file) or die "Could not open '$file' $!\n";

sub write_out
{
    my $batch = shift;

    for my $first_five (keys %$batch)
    {
        my $file_name  = $first_five . ".csv";
        my $need_title = ! -e $file_name;

        open my $fh, '>>', $file_name or die $!;
        print $fh "Title\n" if $need_title;
        print $fh @{ $batch->{$first_five} };
        close $fh;
    }
}

my ($line, $batch, $count);

$batch = { };
$count = 0;

while ($line = <$data>)
{
    next if $. == 1;

    if ($line =~ /^[^,]*,(.....)/)
    {
        push @{ $batch->{$1} }, $line;

        if (++$count > 10000)   # adjust as needed
        {
            write_out $batch;
            $batch = { };
            $count = 0;
        }
    }
}

write_out $batch if $count; # write final batch

close $data;

现在,我确实注意到我的脚本输出与您的脚本输出之间的区别:您的脚本似乎删除了每个目标.csv文件的输出的第一行,并在其中放置了Title一词。 我认为那是一个错误。 我上面的脚本添加了一个名为Title的行,而没有删除给定“前五个”的第一个实例。

如果需要以前的行为,可以在sub write_out进行更改。

我做了一些额外的实验。 我将批处理大小更改为10,000,000,以便write_out仅被调用一次。 内存使用量确实增长了很多,运行时间仅下降到22秒。 我还尝试将批处理大小更改为100。内存使用量显着下降,但运行时间增加了大约30秒。 这表明文件打开/关闭是真正的瓶颈。

因此,通过更改批处理大小,可以控制内存占用量与运行时间。 无论如何,面向批处理的代码应该比您当前的方法快得多。

编辑 :我使用了第二个1000万条记录输入进行了进一步的基准测试,这一次完全随机化了5位数字键。 结果输出写入100,000个名为00000.csv99999.csv文件。 原始脚本运行大约需要3分钟,而我上面的脚本(批处理大小为1000000)大约需要1:26,因此运行速度大约是原来的两倍。

瓶颈不是脚本本身,而是文件系统操作。 创建/更新100,000个文件本质上是昂贵的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM