| |
咨询热线
- 免费咨询电话:
- 400-700-0056
- 800-810-0056
- 教学就业监督电话:
- 400-810-3016
- QQ在线咨询:
- 517589021

- 540118445

- 810143172

- MSN在线咨询:
- upadv01@hotmail.com
- upadv05@hotmail.com
- upadv06@hotmail.com
|
|
文章内容
-
Perl 是一门非常灵活的语言,然而,其易用特性会使程序员滋生出一种懒散的编程习惯。我们应该对这些坏习惯负责,同时可以采取一些快捷步骤来提高 Perl 应用程序的性能。在本文中,我们将介绍优化的一些关键内容,了解哪些解决方案有效、哪些无效,以及如何继续构建并扩展设计时就考虑到优化和速度的应用程序。
拙劣的性能源自草率的编程 坦率地说,我喜欢 Perl,而且到处使用 Perl。我已经使用 Perl 开发了很多 Web 站点,编写了很多管理脚本,并编写了一些游戏。通常使用 Perl 是为了节省时间,并为我自动检查一些信息:从彩票号码到股票价格,我甚至使用 Perl 来自动编写邮件。由于使用 Perl 让一切都变得如此简单,因此很容易忘记对其进行优化。许多情况下,这并不是世界末日。因此多花几个毫秒来查询股票价格或处理日志文件又有什么关系呢?
然而,这些相同的懒惰习惯在小程序中可能只是多花费几毫秒的时间,但是在大规模开发项目中,多耗费的时间就变成数倍了。这就是 Perl 的 TMTOWTDI (There's More Than One Way To Do It) 颂歌开始变坏的地方。如果您需要很快的速度,不管有多少种慢速的方法,但是可能只有一两种方法可以达到最快的结果。最终,即使您可以得到预期的结果,但草率的编程还是会导致拙劣的性能。因此,在本文中,我们将介绍一些可以用来取消 Perl 应用程序额外执行周期的关键技术。
优化方法 首先,有必要随时记住 Perl 是一门编译语言程序。您所编写的源代码是转换为执行的字节码时进行编译的。字节码本身就有一个指令范围,所有的指令都是使用高度优化的 C 语言编写的。然而,即使在这些指令中,有些操作仍然可以进行优化,得到相同的结果,但是执行的效率更高。总体来讲,这意味着您要使用逻辑序列与字节码的组合,后者是从前者中生成的,最终会影响性能。某些相似操作之间性能的差距可能非常巨大。现在让我们考虑清单 1 和清单 2 中的代码。这两段代码都是将两个字符串连接为一个字符串,一个是通过普通的连接方法实现,而另外一个是通过生成一个数组并使用 join 方法进行连接。
清单 1. 连接字符串,版本 1 my $string = 'abcdefghijklmnopqrstuvwxyz'; my $concat = ''; foreach my $count (1..999999) { $concat .= $string; } 清单 2. 连接字符串,版本 2 my $string = 'abcdefghijklmnopqrstuvwxyz'; my @concat; foreach my $count (1..999999) { push @concat,$string; } my $concat = join('',@concat);
执行清单 1 需要 1.765 秒,而执行清单 2 则需要 5.244 秒。这两段代码都生成一个字符串,那么是什么操作耗费了这么多时间呢?传统上讲(包括 Perl 开发组),我们都认为连接字符串是一个非常耗时的过程,因为我们需要为变量扩展内存,然后将字符串及新添加的内容复制到新的变量中。另一方面,向一个数组中添加一个字符串应该非常简单。我们还添加了使用 join() 复制连接字符串的问题,这会额外增加 1 秒的时间。
这种情况下的问题在于,将字符串 push() 到一个字符串中非常耗时;首先,我们要执行一次函数调用(这会涉及压栈和出栈操作),还要添加额外的数组管理工作。相反,连接字符串操作非常简单,只是运行一个操作码,将一个字符串变量附加到一个现有的字符串变量中即可。即使设置数组的大小来减少其他工作的负载(使用 $#concat = 999999),也只能节省 1 秒钟的时间。
上面这个例子是非常极端的一个例子,在使用数组时,速度可以比使用字符串快数倍;如果需要重用一个特定的序列,但要使用不同的次序或不同的空格字符,那么这就是很好的一个例子。当然,如果想重新排列序列的内容,那么数组也非常有用。顺便说一下,在这个例子中,产生一个重复 999,999 次字符的字符串的更简便方法是:
$concat = 999999 x 'abcdefghijklmnopqrstuvwxyz';
这里介绍的很多技术单独使用都不会引起多大的差异,但是当您在应用程序中组合使用这些技术时,就可以在 Perl 应用程序中节省几百毫秒的时间,甚至是几秒的时间。
使用引用 如果使用大型数组或 hash 表,并使用它们作为函数的参数,那么应该使用它们的一个引用,而不应该直接使用它们。通过使用引用,可以告诉函数指向信息的指针。如果不使用引用,就需要将整个数组或 hash 表复制到该函数的调用栈中,然后在函数中再次对其进行复制。引用还可以节省内存(这可以减少足迹和管理的负载),并简化您的编程。
字符串处理 如果在程序中使用了大量的静态字符串,例如,在 Web 应用程序中,那么就要记得使用单引号,而不是使用双引号。双引号会强制 Perl 检查可能插入的信息,这会增加打印字符串的负载:
print 'A string','another string',"n";
我使用逗号来分隔参数,而不是使用句号将这些字符串连接在一起。这样可以简化处理过程;print 只是简单地向输出文件发送一个参数。连接操作会首先将字符串连接在一起,然后将其作为一个参数打印。
循环 正如您已经看到的一样,带有参数的函数调用的开销很高,因为要想让函数调用正常工作,Perl 只能将这些参数压入调用堆栈之后,再调用函数,然后从堆栈中再次接收响应。所有这些操作都需要尽避免我们不需要的负载和处理操作。由于这个原因,在一个循环中使用太多函数调用不是个好主意。同样,这减少了比较的次数。循环 1,000 次并向函数传递信息会导致调用该函数 1,000 次。要解决这个问题,只需要调整一下代码的顺序即可。我们不使用 清单 3 的格式,而是使用清单 4 中的格式。
清单 3. 循环调用函数 foreach my $item (keys %{$values}) { $values->{$item}->{result} = calculate($values->{$item}); } sub calculate { my ($item) = @_; return ($item->{adda}+$item->{addb}); }
点击:查看尚观ULP学员最新就业薪资待遇统计报告!
点击:了解尚观ULP-S专家课程(Linux主机、集群与大型数据库安全方向)
点击:了解尚观ULP-D专家课程(Linux内核、驱动与嵌入式开发方向)
填表获取 Linux、嵌入式、Oracle 技术资料
|