【问题标题】:Quick way of opening multiple files after reading input files in perl在perl中读取输入文件后打开多个文件的快速方法
【发布时间】:2012-08-21 21:30:48
【问题描述】:

我的输入文件(~5k 行)格式看起来像这样

foo0: users/user1/temp1 users/user2/temp1 4.0
foo1: users/user2/temp1 users/user4/temp2 users/user4/temp1 1.0
foo2: users/user1/temp3 users/user2/temp3 2.0
foo4: users/user4/temp5 users/user2/temp6 users/user1/temp1 users/user3/temp1 4.0

我的脚本需要做的是查看每一行,抓取每个路径,打开文件并根据它检查里面的内容。

例如:对于第 1 行,脚本必须打开 user1.txt 并在 user1.txt 中搜索 temp1 并执行一些操作。然后继续到 user2.txt 并在里面寻找 temp1 并做一些事情。

对于第 2 行:打开 users2.txt 并搜索 temp1;打开 users4.txt 并搜索 temp2;打开 users4.txt 并搜索 temp1。

最快的方法是什么。我目前是一个一个的打开和关闭,这似乎需要很长时间。任何帮助表示赞赏,谢谢!

【问题讨论】:

  • 有多少个文件,有多大?如果您有 3 个文件,每 10 行长,或者每 100 万行长 100 万行,这会有所不同。
  • 请回答理查德的问题。如果userN.txt 文件的数量有限,那么您可以一次打开所有这些文件。至少您可以安排对每个文件的所有查询一起完成,而不是关闭并重新打开它们。请给我们更多信息
  • 当事情进展缓慢时,使用Devel::NYTProf 之类的配置文件,发现缓慢的位,然后处理这些问题。

标签: perl


【解决方案1】:

我会这样做:

#! /usr/bin/perl

use warnings;
use strict;

while ( <> ) { 

    ## Remove last newline character.
    chomp;

    ## Split line with spaces and save paths (all strings but the first and
    ## last one).
    my @paths = split;
    @paths = @paths[ 1 .. $#paths - 1 ];

    ## For each path...
    for my $path ( @paths ) { 

        ## Split with a slash, get second field and try to open it. 
        my @elements = split m|/|, $path;
        open my $fh, q|<|, $elements[1] or die $!; 

        ## Read line by line searching for the third field of the path, do
        ## something if found. You can add a 'last' instruction if you wish.
        while ( my $line = <$fh> ) { 
            chomp;
            if ( $line =~ m/\Q${elements[2]}\E/ ) { 
                ## Do something;
            }   
        }   

        close $fh or warn $!; 
    }   
}

【讨论】:

  • 这是一个相当于提问者已经说过的解决方案:“我现在一个一个打开和关闭,这似乎需要很长时间。”它仍然存在可能导致缓慢的基本问题:如果在输入中出现多次,则打开并读取 user1.txt 多次。
【解决方案2】:

嗯,在普通系统上,硬盘数据传输速度是限制。但是有些方法可能会给你带来优势:

多线程

如果您担心在此程序运行时您的硬盘可能处于空闲状态,或者您从多个物理驱动器读取数据,您可能需要尝试多线程。您应该注意,如果执行错误(a),如果您的 HDD 读取头必须跳动,这可能会使您的程序运行更慢或 (b)太多了。

  1. 使用pipe 函数打开n 个管道,其中n 是线程数。
  2. fork n 次来自主(“boss”)线程。
    1. 每个工作线程都会关闭所有不相关的管道
  3. boss 线程读取您的输入文件并将每个命令通过管道传递给不同的进程依次。这样一来,所有工作进程都有相同的工作量。
  4. 工作线程执行您的搜索等操作。

如果您之前没有使用fork 进行多线程处理,那么此解决方案将不适合您。

而且,如上所述,当您对每个文件的计算成本很高时(当进行计算/搜索的时间与阅读所花费的时间相当时),这不太可能产生积极的结果除了如果您的脚本消耗大量 CPU 并且您有多个处理器,这可能会有所帮助。

想出一个更好的算法

  • 您在每个文件中搜索什么以及如何搜索?您是否只针对每一行匹配一个正则表达式,然后执行一些代码?什么代码?正则表达式是否过于复杂?
  • 您可以使用一些启发式方法来跳过文件的特定部分吗?
  • 你试过Tie::File吗?这样可以避免将文件加载到内存中,这可能会有所帮助。
  • 您是否对脚本进行了基准测试?有关介绍,请参阅此tutorial on perl.com。哪些部分运行缓慢?
  • 能否降低程序的算法复杂度?即:您是否在任何文件上迭代两次?这可能不是最理想的。

【讨论】:

  • 我不认为多线程在这里是一个很好的第一个建议。诚然,我们对这个问题知之甚少,但在极少数情况下需要这样做。而且它增加了很多复杂性和许多陷阱。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
  • 2018-02-25
  • 1970-01-01
  • 2010-10-02
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
相关资源
最近更新 更多