免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6244 | 回复: 14
打印 上一主题 下一主题

自己写了个Perl脚本,但是运行很慢,麻烦各位好汉走过路过帮忙看看 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2018-04-03 10:31 |只看该作者 |倒序浏览
大家好,我写了个脚本但是脚本运行的特别慢,但是文件小的话(假设2000行左右)就可以马上运行出来,但是文件大就特别慢好几天了才出来一点点结果(400K左右)感觉不太正常,麻烦大家帮忙看看如何修改才能让它运行速度加快,自己也不怎么懂算法,再此谢过了:具体情况见下述   我需要对一个4G左右大小的文件进行处理,该文件内容是这样的----

ID1  xxx  xxx xxx 50                                   
ID1  xxx  xxx xxx 60                                   ID1  xxx  xxx xxx 60    即第5列是个分值,分值高则留下,分值一样则都保留,ID重复的次数是>=2, 绝大部分是>=2的
ID2  xxx  xxx xxx 50                                   ID2  xxx  xxx xxx 60   
ID2  xxx  xxx xxx 60   最终需要得到右边结果    ID4  xxx  xxx xxx 60

ID3  xxx  xxx xxx 50                                   ID4  xxx  xxx xxx 60
ID3  xxx  xxx xxx 60                                   ID3  xxx  xxx xxx 60

ID3  xxx  xxx xxx 60                                   ID3  xxx  xxx xxx 60
ID4  xxx  xxx xxx 60
ID4  xxx  xxx xxx 60  (xxx所表示的是不一样的,所以只是ID 相同行不同)


while(<IN>){
    chomp;
    my($z,$c)=(split /\t/)[0,4];
    $hash{$z}++;
    if($hash{$z}==1){
         $hash2{$z}=$_;
         $hash4{$z}=$c;
     }
    if($hash{$z}>1){
         $hash3{$z}=$_;
         $hash5{$z}=$c;
     }
}
foreach my $key2(sort keys %hash2){
     foreach my $key3(sort keys %hash3){
          if($key2 eq $key3){
             if($hash4{$key2}>$hash5{$key3}){
               print OUT "$hash2{$key2}\n";
            }
             if($hash4{$key2}<$hash5{$key3}){
               print OUT "$hash3{$key3}\n"
           }
             if($hash4{$key2}==$hash5{$key3}){
                print OUT "$hash2{$key2}\n$hash3{$key3}\n";
           }
     }
  }}


论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
2 [报告]
发表于 2018-04-03 13:59 |只看该作者
你把所有数据都放内存里,4G的文件占用内存可能要40G到400G

如果有3个ID一样,你这代码不能正确处理。

优化思路:如果ID是排过序的,相同的连着内存占用就是O(1)常量,处理时间只跟文件行数相关O(n)

论坛徽章:
0
3 [报告]
发表于 2018-04-03 15:43 |只看该作者
回复 2# zhlong8
非常感谢你的回答,谢谢!
文件我是已经提前排好序了的,您的思路是  如果相同的ID连续出现,就赋值给一个常量(假设赋值给1),是这个意思么?这样一来也是要进行计算重复的次数的。
我再请教一个问题:  脚本运行慢是因为我把文件的每一行都存进内存里,是if(....)判断后再将$_存入哈希里这里出错了是么,这样就是存进内存么?
这个是我写的另外一个脚本,我也是把$_存进$hash里面,文件也很大但是这个运行速度就快
while(<DATA>{
   chomp;
   my($c,$d)=(split/\t/)[0,4];
   $hash{$c}=$_;    #这里也是将其存进内存么?
   $hash2{$c}++;   
   $hash3{$c}=${d}
}  

foreach my $key3(sort keys %hash3){    #还是遍历的时候会存进内存
   if($hash2{$key3}>1){
         print OUT "$hash{$key3}\n";

   }else{
         print OUTTTT "$hash{$key3}\n";
     }
}







论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
4 [报告]
发表于 2018-04-03 23:26 |只看该作者
本帖最后由 zhlong8 于 2018-04-03 23:27 编辑

先写正确再优化啊。既然已经排过序了,一个ID一个ID的处理不就行了,根本不用保存到 hash 中去。
  1. use 5.010;
  2. use strict;
  3. use warnings;

  4. my $last_id = '';
  5. my $last_score;
  6. my @queue;

  7. while (<>) {
  8.     my($id, $score) = (split /\t/)[0,4]; #每个字段位置固定的话可以用 substr
  9.     if ($id ne $last_id) { #处理完一组直接打印,无需保留中间结果
  10.         print for @queue;
  11.        @queue     = $_; #等价于清空数组长度变为0,然后 $queue[0] = $_;
  12.         $last_id    = $id;
  13.         $last_score = $score;
  14.     } elsif ($score == $last_score) {
  15.         push @queue, $_;
  16.     } elsif ($score > $last_score) {
  17.         $last_score = $score;
  18.         @queue      = $_;
  19.     }
  20. }

  21. print for @queue;
复制代码


思路基本上就这样了,这么频繁的读写的话IO可能成为瓶颈,不过你要先测一下。

论坛徽章:
42
19周年集字徽章-周
日期:2019-10-14 14:35:31平安夜徽章
日期:2015-12-26 00:06:30数据库技术版块每日发帖之星
日期:2015-12-01 06:20:002015亚冠之首尔
日期:2015-11-04 22:25:43IT运维版块每日发帖之星
日期:2015-08-17 06:20:00寅虎
日期:2014-06-04 16:25:27狮子座
日期:2014-05-12 11:00:00辰龙
日期:2013-12-20 17:07:19射手座
日期:2013-10-24 21:01:23CU十二周年纪念徽章
日期:2013-10-24 15:41:34IT运维版块每日发帖之星
日期:2016-01-27 06:20:0015-16赛季CBA联赛之新疆
日期:2016-06-07 14:10:01
5 [报告]
发表于 2018-04-04 08:33 |只看该作者
我理解就是把最高分的id挑出来
那么用一个变量存最高分,用一个hash存分数等于最高分的id xxx xxx xxx
如果最高分变了,就清空hash,
这样从头到尾过一遍。
不需要排序吧。
perl的文本处理速度大约是1分钟1G左右。

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
6 [报告]
发表于 2018-04-04 12:05 |只看该作者
回复 1# Chinaaa123

$ cat file
ID1  xx1  xxx xxx 50                                   
ID1  xx2  xxx xxx 60
ID2  xx3  xxx xxx 50
ID2  xx4  xxx xxx 60
ID3  xx5  xxx xxx 50
ID3  xx6  xxx xxx 80
ID3  xx7  xxx xxx 80
ID4  xx8  xxx xxx 70
ID4  xx9  xxx xxx 70

$ perl get_max_val.pl file
ID1  xx2  xxx xxx 60
ID2  xx4  xxx xxx 60
ID3  xx6  xxx xxx 80
ID3  xx7  xxx xxx 80
ID4  xx8  xxx xxx 70
ID4  xx9  xxx xxx 70

$ cat get_max_val.pl

use strict;
use warnings;

# get max value and string by sorted data
my $sMax_val = 0;
my $sMax_str = "";
my $sId = "";

while(<>){
  chomp;
  next if m/^\s*$/;
  s/^\s+|\s+$//g;
  my @aData = split;
  if ($sId ne $aData[0]){
    print $sMax_str if($sMax_str ne "");
    $sMax_val = $aData[-1];
    $sMax_str = "$_\n";
    $sId = $aData[0];
    next;
  }
  if ($sMax_val < $aData[-1]){
    $sMax_val = $aData[-1];
    $sMax_str = "$_\n";
    next;
  }
  if ($sMax_val == $aData[-1]){
    $sMax_str .= "$_\n";
    next;
  }

}
print $sMax_str;

论坛徽章:
0
7 [报告]
发表于 2018-04-04 14:32 |只看该作者
你的文件重要不?不重要的话打个包上传上来

论坛徽章:
0
8 [报告]
发表于 2018-04-04 14:38 |只看该作者
perl有没有pandas? 这种数据pandas处理的快

论坛徽章:
0
9 [报告]
发表于 2018-04-04 16:06 |只看该作者
哇,
在此感谢上述各位大神的回复,谢谢你们的帮助!
我的问题解决了,再次感谢!抱拳

论坛徽章:
0
10 [报告]
发表于 2018-04-04 16:15 |只看该作者
回复 8# dahe_1984

pandas是Python快速处理数据的一个工具,我感觉Perl本身就类似于pandas吧,也不知道理解的对不对,谢谢你的回答!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP