Featured Posts

纠结与释怀 这几天的纠结让我度日如年,伴随我的是焦虑和失眠。好久没有这样的感觉了。 我总是患得患失,这是一种心理问题,在做选择的时候,反复对比各方的优劣,放不下东,也舍不得西。 自己不知道怎么选择,然后反复问家人和朋友,即使问到答案,也不能让自己安心顺从。 幸运的是,在反复纠结之后,我逐渐想明白了一些道理。 选择,就要付出代价,必定有所得有所失,我应该勇敢承担起责任,坦然面对自己的选择带来的变化和影响。 纠结的时候,我感觉自己是个懦弱的人,害怕犯错,害怕不好的结果。 现在,我鼓起勇气,自己做出选择,不管对错,我接受,不后悔。 我要感谢猛哥,花费很多时间和精力,前后沟通,给我提供了非常难得的机会,在我最终没有选择这个机会的时候,仍然支持我的选择,并告诉我他这里的大门永远向我敞开。 此时,时间像突然停止了一样,飞快打字的手,也一下停住了,我反复看着这句话,感觉到眼眶周围热热的,滑滑的…… 我想我的勇气,多半来自于猛哥对我的关照。 我只求将来有机会能够报答猛哥的知遇之恩。 是时候为自己的选择努力工作了,大家一起加油!

Readmore

CentOS: cannot restore segment prot after reloc 最近在研究CentOS,用xampp装一套集成的LAMP环境,结果在启动Apache的时候报错: cannot restore segment prot after reloc: Permission denied 原因是 modules/mod_perl.so 不能加载。 查了一下可能是SELINUX的问题,有一个解决方法: 用 chcon...

Readmore

PHP 文件下载 IE 无法打开页面 IE 又有一个弱得不行的问题让我发现! 有个项目,要限制文件的下载权限,只有注册用户才可以下载,用户登录后,点击下载链接,弹出保存附件的提示。 我用...

Readmore

Subversion neon 诡异配置 一波三折 今天发现前几天装的 subversion 居然没法通过 http 协议访问版本库! Subversion 出现 svn: Unrecognized URL scheme for 'http://.....'  这样的错误提示。 检查 svn 客户端是否支持...

Readmore

  • Prev
  • Next

pure function

Posted on : 18-10-2007 | By : leakon | In : Develop, Perl, 转载

1

A pure function:

Has no side effects

Return value depends only on arguments

Example:

sub factorial {
my $n = shift;
$n == 0 ? 1 : $n * factorial($n-1);
}

cache 只对 pure function 有意义

这可以思考查询一个档案的修改时间的这种 function,他并非一个 pure function,所以对非 pure function cache 是没有意义的这里有一个例子

Highly Recursive Functions
sub fib {
my ($n) = @_;
return $n if $n ==0 || $n == 1;
return fib($n-2) + fib($n-1);
}

This function is very very slow!

Caching Fixes Recursion
Solution: Caching

@fib = (0, 1);
sub fib {
my ($n) = @_;
return $fib[$n] if defined $fib[$n];
return $fib[$n] = fib($n-1) + fib($n-2);
}

fib(20) computes fib(18) and fib(19)

fib(19) goes to compute fib(18)

But it is already in $fib[18]

Function is now very fast,Almost as fast as a pure iterative version,
Unlike the iterative version, this version required no ingenuity

以上文章节录自 http://perl.plover.com/yak/hw-dcpm/

Perl 变量魔法

Posted on : 25-09-2007 | By : leakon | In : Perl, 原创

0

先来看一段 Perl 脚本:

sub showVars {

my $name = "first";
print $name . "\t at " . \$name . "\n";
for(my $i = 0; $i < 2; $i++) {
my $name = "loop_" . $i;
if (1 < 3) {
print $name . "\t at " . \$name . "\n";
my $name = "if_A";
print $name . "\t at " . \$name . "\n";
{
my $name = "blank";
print $name . "\t at " . \$name . "\n";
}
print $name . "\t at " . \$name . "\n";
}
if (1 < 4) {
print $name . "\t at " . \$name . "\n";
my $name = "if_B";
print $name . "\t at " . \$name . "\n";
}
print $name . "\t at " . \$name . "\n";
}
print $name . "\t at " . \$name . "\n";
}

sub showVars_2 {

my $name = "first";
print $name . "\t at " . \$name . "\n";
for(my $i = 0; $i < 2; $i++) {
$name = "loop_" . $i;
if (1 < 3) {
print $name . "\t at " . \$name . "\n";
$name = "if_A";
print $name . "\t at " . \$name . "\n";
{
$name = "blank";
print $name . "\t at " . \$name . "\n";
}
print $name . "\t at " . \$name . "\n";
}
if (1 < 4) {
print $name . "\t at " . \$name . "\n";
$name = "if_B";
print $name . "\t at " . \$name . "\n";
}
print $name . "\t at " . \$name . "\n";
}
print $name . "\t at " . \$name . "\n";
}

showVars();
print "--------------\n";
showVars_2();

这里面有 2 个函数,两者之间的区别,就是变量的定义方式不同。

第一个函数,多次使用 my 声明变量。Perl 会在每一个局部区域内,比如说大括号 {} 内,实现一个命名空间。
也就是说,在不同的代码段,相同的变量名,实际上指向了不同的内存地址。
第一个函数体内,首先声明了一个变量 $name,他的作用域是整个函数,但在 for 循环体内,又用 my 声明了 $name 变量,因为 for 是一个封闭的结构,在 {} 里面就可以产生一个新的命名空间,此时 $name 指向了一个新的内存地址。这一点可以在后面的输出结果中看到。

由此,引发一个值得思考的问题:
如果在循环体内部用 my 去声明变量,那么循环执行多少次,就会有多少个变量的副本,这会浪费很多内存空间。
这一点是跟其他类 C 语言是有很大区别的。
所以,如果你要想利用 Perl 的命名空间,那么只要多注意代码段的作用范围,编程的时候能感受到 Perl 十分强大的便利性。
需要注意的,就是避免在循环体中使用 my 声明,浪费内存空间不说,还会影响程序的性能。

说了半天,还是看一看实际的结果吧:

$ perl show_vars.pl
first at SCALAR(0x182fb10)
loop_0 at SCALAR(0x182fbb8)
if_A at SCALAR(0x182fc24)
blank at SCALAR(0x182fc84)
if_A at SCALAR(0x182fc24)
loop_0 at SCALAR(0x182fbb8)
if_B at SCALAR(0x182fd5c)
loop_0 at SCALAR(0x182fbb8)
loop_1 at SCALAR(0x182fd5c)
if_A at SCALAR(0x182fc84)
blank at SCALAR(0x276164)
if_A at SCALAR(0x182fc84)
loop_1 at SCALAR(0x182fd5c)
if_B at SCALAR(0x182fc24)
loop_1 at SCALAR(0x182fd5c)
first at SCALAR(0x182fb10)
--------------
first at SCALAR(0x182fe88)
loop_0 at SCALAR(0x182fe88)
if_A at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)
loop_1 at SCALAR(0x182fe88)
if_A at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)

PHP Perl 关联数组 哈希表 Hash Table

Posted on : 18-09-2007 | By : leakon | In : PHP, Perl, 原创

2

关联数组,又称为哈希表(hash table),是一种非常好用的数据结构。

在程序中,我们可能会遇到需要消重的问题,举一个最简单的模型:

有一份用户名列表,存储了 10000 个用户名,没有重复项;
还有一份黑名单列表,存储了 2000 个用户名,格式与用户名列表相同;
现在需要从用户名列表中删除处在黑名单里的用户名,要求用尽量快的时间处理。

这个问题是一个小规模的处理量,如果实际一点,2 个表都可能很大,比如有 2 亿条记录。

我最开始想到的方法,就是做一个嵌套的循环,设用户名表有 M 条记录,黑名单列表有 N 条记录,那么,循环的次数是 M * N 次!
PHP 版代码:

foreach($arrayM as $keyM => $nameM) {
foreach($arrayN as $nameN) {
if ($nameM == $nameN) {
// 本行执行了 M * N 次!
unset($arrayM[$keyM]);
}
}
}
return $arrayM;
?>

另一种方式,利用数组索引。

PHP 是一种弱类型的语言,不像 C 语言那样有严格的变量类型限制。C 语言的数组,每一个元素的类型必须一致,而且索引都是从 0 开始。
PHP 的数组,可以用字符串作为索引,也称为关联数组。
数组索引,有一个天然的限制就是不会重复,而且访问的时候不需要查找,可以直接定位。

还是刚才的那个问题,我们采用另一种办法。

把黑名单列表的用户名组织到一个数组里,数组的索引就是用户名。

然后,遍历用户列表的时候,只需直接用 isset 查询那个用户名是否存在即可。

PHP 版代码:

$arrayHash = array();
foreach($arrayN as $nameN) {
// 本行执行了 N 次。
$arrayHash[$nameN] = 1;
}

foreach($arrayM as $keyM => $nameM) {
if (isset($arrayHash[$nameM])) {
// 本行执行了 M 次!
unset($arrayM[$keyM]);
}
}
return $arrayM;
?>

可以看到,优化过的代码,循环次数是 M + N 次。

假如 M 和 N 都是 10000,优化前,循环了 1 亿次;优化后,只循环了 20000 次,差了 5000 倍!
如果第二个程序耗时 1 秒,则第一个程序需要将近一个半小时!

最近在做 Perl 的开发,Perl 在处理文本的时候有很高的效率,同样,它也支持关联数组!

只是语法和 PHP 的那种类 C 的方式有很大不同,以第二段代码为例,Perl 版的实现:


#!/usr/bin/perl
my %arrayHash;
for(my $i = 0; $i < @arrayN; ++$i) {
$arrayHash{$arrayN[$i]} = 1;
}

for(my $i = 0; $i < @arrayM; ++$i) {
if ($arrayHash{$arrayM[$i]}) {
$arrayM[$i] = undef;
}
}

Perl 的数组是 @ 开头,哈希是以 % 开头,unset 实际上就是 undef。
Perl 的哈希和数组都是有具体类型的,而且向函数传递变量的时候要传引用,我刚学时间不长,快被搞晕了。

不过,现在刚刚实现了一个以 hash 方式进行 IP 位置查找的算法,平均比较次数大概在 3 次左右,比传统的折半查找方式少了很多次,它大概需要 8 次以上的比较。

刚刚做了一个小的性能测试,对 10 万个 IP 进行查找,在我的台式机上,耗时 15 秒,平均每秒 7500 次,感觉还不错,呵呵。

不过,还是喜欢 PHP 的数组,真的很强大!

God Bless PHP!