免费注册 查看新帖 |

Chinaunix

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

哪位大牛能帮忙优化下代码,转个测试.. [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-04-25 16:45 |只看该作者 |倒序浏览
以下3个文件依次是用python、awk和perl写的脚本,做同一件事情:
diff.sh f1 f2
f1和f2每一行的第一个字段(以空格分割)为key,如果f2某一行的key在f1中不存在,则输出f2该行。

比如:
a.dat的内容是
1 a
2 a

b.dat的内容是
1 b
3 b

那么diff.sh a.dat b.dat则输出
3 b

代码:
diff.py

#!/usr/bin/python
import sys
if len(sys.argv) != 3:
    print "Usage: " + sys.argv[0] + "file1 file2";
    sys.exit(-1);

file1 = sys.argv[1]
file2 = sys.argv[2]

list1 = {};
for line in open(file1):
    list1[line.split()[0]] = 1;

for line in open(file2):
    key = line.split()[0];
    if key not in list1:
        sys.stdout.write(line)

diff.sh

#!/bin/sh
if [[ $# < 2 ]];then
    echo "Usage: $0 file1 file2"
    exit
fi

function do_diff()
{
    if [[ $# < 2 ]];then
        echo "Usage: $0 file1 file2"
        return 1
    fi
    if [[ ! -f $1 ]];then
        echo "$1 is not file"
        return 2
    fi
    if [[ ! -f $2 ]];then
        echo "$2 is not file"
        return 3
    fi

    awk '
        BEGIN{FS=OFS=" "}
        ARGIND == 1 {
            arr[$1] = 1;
        }
        ARGIND == 2 {
            if (!($1 in arr)) {
                print $0;
            }
        }
    ' $1 $2
}

do_diff $1 $2

diff.pl

#!/usr/bin/perl -w
exit if (1 > $#ARGV);

my %map_orig;

my $file_orig = shift @ARGV;
open FH, "<$file_orig" or die "can't open file: $file_orig";
while (<FH>) {
        chomp;
        #$map_orig{$_} = 1;
        my ($filed) = split /\s+/;
        $map_orig{$filed} = 1;
}
close (FH);

my $file_diff = shift @ARGV;
open FH, "<$file_diff" or die "can't open file: $file_diff";
while (<FH>) {
        chomp;
        my ($filed) = split /\s+/;
        print "$_\n" if (!defined$map_orig{$filed});
}
close (FH)


diff2.pl

#!/usr/bin/perl -w
exit if (1 > $#ARGV);

my %map_orig;

my $file_orig = shift @ARGV;
open FH, "<$file_orig" or die "can't open file: $file_orig";
while (<FH>) {
        chomp;
        #$map_orig{$_} = 1;
        my ($filed) = split(" ");
        $map_orig{$filed} = 1;
}
close (FH);

my $file_diff = shift @ARGV;
open FH, "<$file_diff" or die "can't open file: $file_diff";
while (<FH>) {
        chomp;
        my ($filed) = split(" ");
        print "$_\n" if (!defined$map_orig{$filed});
}
close (FH)
以上4个文件的算法都是一样的,把第一个文件的key读取放到一个map中,再读取第2个文件的key,判断是否在该map中,不是则打印到标准输出。diff.pl和diff2.pl的区别是前者用了正则,后者是用字符串匹配。

测试方法:time diff.xx f1 f2 > out

测试文件f1有123183923行,每一行格式为:
key value(两个字段)
文件大小为2.5G

f2有439116行,每一行的格式也是:
key value(两字段)
文件大小为5.6M

测试结果(time real):
diff.py的时间为3m46s = 226s
diff.sh的时间为3m49s = 229s
diff.pl的时间为(7m21s + 7m12s) = 437s
diff2.pl的时间为(7m41s + 7m34s)/2 = 454s
结果显示awk和python的性能差不多,perl则要明显差些。看来python的dict优化得很好,居然能赶上awk的性能,很出乎我的意料。

以上测试在同一台机器上跑,测试环境一样,但非严格公平(不同时间内机器负载等可能略有不同)。

--------------
有人质疑diff.pl是用了正则导致了效率降低,于是我取消了正则,用简单的字符串匹配,结果性能并没有预期的得到提升,相反,甚至有了一点点下降。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
2 [报告]
发表于 2011-04-25 16:58 |只看该作者
太愚蠢了,难道不是把 file2 放到内存里吗?

论坛徽章:
0
3 [报告]
发表于 2011-04-25 17:37 |只看该作者
老大说中要害了,这个算法实在是不敢恭维!

抛开算法不说,PERL代码也不好,既然只需第一列,那还chomp做什么,chomp也是需要时间的。

PERL确实有些老了,与新兴语言相比,它的优势不在这里。

论坛徽章:
0
4 [报告]
发表于 2011-04-25 21:11 |只看该作者
这是看别人的一篇文章..唉...perl啊 。。。

论坛徽章:
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
5 [报告]
发表于 2011-04-25 21:29 |只看该作者
本帖最后由 zhlong8 于 2011-04-25 21:31 编辑

python 那个写的很简洁,Perl 那个很多无用的操作和复制字符串啊。简化下

#!/usr/bin/perl

use strict;

exit if @ARGV > 2;

my %map_orig;

my $file_orig = $ARGV[0];
open FH, '<', $file_orig or die "can't open file: $file_orig";

while (<FH>) {
    my $filed = (split /\s+/)[0];
    $map_orig{$filed} = 1;
}

my $file_diff = $ARGV[1];
open FH, '<', $file_diff or die "can't open file: $file_diff";

while (<FH>) {
    my $filed = (split /\s+/)[0];
    print unless exists $map_orig{$filed};
}

论坛徽章:
0
6 [报告]
发表于 2011-04-26 11:21 |只看该作者
简单测试了一下,模拟生成数据文件,f1共7839116行,112MB,f2共439116行,6.28MB,在我的电脑上简单测试结果如下:

1、楼主的Perl代码:35 wallclock secs (34.14 usr +  0.70 sys = 34.85 CPU)
2、对楼主的Perl代码进行简化,去除一些不必要的代码:34 wallclock secs (32.31 usr +  0.72 sys = 33.03 CPU)
3、改变算法,将f2读入内存后进行计算:26 wallclock secs (25.38 usr +  0.42 sys = 25.80 CPU)

我的内存有限,再大的文件测试,我等不了那么久。f1文件越大,代码间的效率差异越明显。象这样的问题,楼主应该改变算法。

在计算机硬件越来越强大的今天,Perl的效率不再是重要问题,与其他脚本语言的差异不会很明显,建议楼主多留意Perl的优点以及好的算法。

论坛徽章:
0
7 [报告]
发表于 2011-04-27 16:42 |只看该作者
非常感谢各位。。我那个是转帖的,不是我的。。。不过也学到了很多。。感谢。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP