Python与perl排序性能

Python与perl排序性能,python,performance,perl,sorting,Python,Performance,Perl,Sorting,解决方案 这解决了我的Perl代码(加上额外的实现代码…:-)的所有问题。总之,Perl和Python都同样出色 use WWW::Curl::Easy; 感谢所有回复者,非常感谢 编辑 我使用的Perl代码似乎大部分时间都在执行http get,例如: my $start_time = gettimeofday; $request = HTTP::Request->new('GET', 'http://localhost:8080/data.json'); $response = $u

解决方案

这解决了我的Perl代码(加上额外的实现代码…:-)的所有问题。总之,Perl和Python都同样出色

use WWW::Curl::Easy;
感谢所有回复者,非常感谢

编辑

我使用的Perl代码似乎大部分时间都在执行http get,例如:

my $start_time = gettimeofday;
$request = HTTP::Request->new('GET', 'http://localhost:8080/data.json');
$response = $ua->request($request);
$page = $response->content;
my $end_time = gettimeofday;
print "Time taken @{[ $end_time - $start_time ]} seconds.\n";
结果是:

Time taken 74.2324419021606 seconds.
20.3471381664
比较我的python代码:

start = time.time()
r = requests.get('http://localhost:8080/data.json', timeout=120, stream=False)

maxsize = 100000000
content = ''
for chunk in r.iter_content(2048):
    content += chunk
    if len(content) > maxsize:
        r.close()
        raise ValueError('Response too large')

end = time.time()
timetaken = end-start
print timetaken
结果是:

Time taken 74.2324419021606 seconds.
20.3471381664
在这两种情况下,排序时间都低于秒。因此,首先,我为这个误导性的问题道歉,这对我来说是另一个教训,永远不要做出假设……:)

我不确定现在该怎么处理这个问题。也许有人可以提出一种更好的方法来用perl执行请求

编辑结束

这只是一个关于Perl与Python中排序性能差异的快速问题。这不是关于哪种语言更好/更快的问题等等,我首先用perl编写了这篇文章,注意到排序所花费的时间,然后尝试用python编写同样的东西,看看它有多快。我只是想知道,如何使perl代码的执行速度与python代码一样快?

假设我们有以下json:

["3434343424335": {
        "key1": 2322,
        "key2": 88232,
        "key3": 83844,
        "key4": 444454,
        "key5": 34343543,
        "key6": 2323232
    },
"78237236343434": {
        "key1": 23676722,
        "key2": 856568232,
        "key3": 838723244,
        "key4": 4434544454,
        "key5": 3432323543,
        "key6": 2323232
    }
]
假设我们有一个大约30k-40k条记录的列表,我们想按其中一个子键进行排序。然后,我们希望构建一个按子键排序的新记录数组

Perl-大约需要27秒

my @list;
$decoded = decode_json($page);
foreach my $id (sort {$decoded->{$b}->{key5} <=> $decoded->{$a}->{key5}} keys %{$decoded}) {
    push(@list,{"key"=>$id,"key1"=>$decoded->{$id}{key1}...etc));
}
对于perl代码,我尝试使用以下调整:

use sort '_quicksort';  # use a quicksort algorithm
use sort '_mergesort';  # use a mergesort algorithm

你的基准是有缺陷的,你在基准测试多个变量,而不是一个。它不仅是对数据进行排序,还进行JSON解码、创建字符串和附加到数组。你不知道花了多少时间分类,花了多少时间做其他事情

更糟糕的是,Perl中有几个不同的JSON实现,每个实现都有各自不同的性能特征。更改基础JSON库,基准将再次更改

如果您想要进行基准排序,则必须更改基准代码,以消除从基准加载测试数据的成本,不管是否使用JSON

Perl和Python都有自己的内部基准库,可以对单个函数进行基准测试,但它们的指令插入会使它们的性能远远低于现实世界中的性能。每个基准测试实现的性能阻力将不同,可能会引入错误的偏差。这些基准库对于比较同一程序中的两个函数更有用。对于语言之间的比较,请保持简单

要获得准确的基准测试,最简单的方法是使用挂钟在程序中计时

# The current time to the microsecond.
use Time::HiRes qw(gettimeofday);

my @list;
my $decoded = decode_json($page);

my $start_time = gettimeofday;

foreach my $id (sort {$decoded->{$b}->{key5} <=> $decoded->{$a}->{key5}} keys %{$decoded}) {
    push(@list,{"key"=>$id,"key1"=>$decoded->{$id}{key1}...etc));
}

my $end_time = gettimeofday;

print "sort and append took @{[ $end_time - $start_time ]} seconds\n";
#当前时间为微秒。
使用时间::雇佣qw(gettimeofday);
我的@list;
my$decoded=decode_json($page);
我的$start\u time=gettimeofday;
foreach my$id(排序{$decoded->{$b}->{key5}$decoded->{$a}->{key5}}}键%{$decoded}){
推送(@list,{“key”=>$id,“key1”=>$decoded->{$id}{key1}…等));
}
我的$end\u time=gettimeofday;
打印“排序和追加花费了@{[$end\u time-$start\u time]}秒\n”;
(我把Python版本留作练习)

从这里您可以改进您的技术。您可以使用CPU秒数而不是挂钟。阵列附加和创建字符串的成本仍然涉及到基准测试中,它们可以被消除,因此您只是基准测试排序。等等

此外,您可以使用查找程序在何处花费时间。这些与基准测试库具有相同的原始性能注意事项,结果仅用于查找程序在何处使用的时间百分比,但快速查看基准测试是否有意外阻力将非常有用


重要的是要对你认为你正在进行的基准测试进行基准测试。

这里还有其他一些东西在起作用;我可以在半秒钟内运行你的排序。改进排序算法与其说取决于排序算法,还不如说是减少每次比较运行的代码量;一个施瓦茨变换可以使它达到三分之一秒,一个Guttman-Rosler变换orm将时间缩短到四分之一秒:

#!/usr/bin/perl
use 5.014;
use warnings;

my $decoded = { map( (int rand 1e9, { map( ("key$_", int rand 1e9), 1..6 ) } ), 1..40000 ) };

use Benchmark 'timethese';

timethese( -5, {
    'original' => sub {
        my @list;
        foreach my $id (sort {$decoded->{$b}->{key5} <=> $decoded->{$a}->{key5}} keys %{$decoded}) {
            push(@list,{"key"=>$id,%{$decoded->{$id}}});
        }
    },
    'st' => sub {
        my @list;
        foreach my $id (
            map $_->[1],
            sort { $b->[0] <=> $a->[0] }
            map [ $decoded->{$_}{key5}, $_ ],
            keys %{$decoded}
        ) {
            push(@list,{"key"=>$id,%{$decoded->{$id}}});
        }
    },
    'grt' => sub {
        my $maxkeylen=15;
        my @list;
        foreach my $id (
            map substr($_,$maxkeylen),
            sort { $b cmp $a }
            map sprintf('%0*s', $maxkeylen, $decoded->{$_}{key5}) . $_,
            keys %{$decoded}
        ) {
            push(@list,{"key"=>$id,%{$decoded->{$id}}});
        }
    },
});
!/usr/bin/perl
使用5.014;
使用警告;
my$decoded={map((int rand 1e9,{map((((('key$,int rand 1e9),1..6)}),1..40000)};
使用基准“timethis”;
这些时间(-5{
“原始”=>sub{
我的@list;
foreach my$id(排序{$decoded->{$b}->{key5}$decoded->{$a}->{key5}}}键%{$decoded}){
推送(@list,{“key”=>$id,%%{$decoded->{$id}});
}
},
'st'=>子系统{
我的@list;
foreach我的$id(
地图$\u->[1],
排序{$b->[0]$a->[0]}
map[$decoded->{$\}{key5},$\],,
密钥%{$decoded}
) {
推送(@list,{“key”=>$id,%%{$decoded->{$id}});
}
},
“grt”=>sub{
我的$maxkeylen=15;
我的@list;
foreach我的$id(
map substr($\u,$maxkeylen),
排序{$b cmp$a}
映射sprintf(“%0*s”,$maxkeylen,$decoded->{${key5})。$\,
密钥%{$decoded}
) {
推送(@list,{“key”=>$id,%%{$decoded->{$id}});
}
},
});

不要为每条记录创建新的散列。只需将密钥添加到现有的散列中即可

$decoded->{$_}{key} = $_
   for keys(%$decoded);

my @list = sort { $b->{key5} <=> $a->{key5} } values(%$decoded);

你研究过Python使用哪种类型的排序吗?你可能还想看看。这是一种Timsort,因此有维基百科链接。有人建议这是一种更好的算法,但我建议这里可能涉及更多因素,包括哈希查找。一个大的区别是:Python,使用
参数来
排序
,只对每个列表元素应用一次键函数(O(n))。另一方面,Perl必须在每次比较时检索排序键(O(n lg n))。这至少有助于增加