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

- 540118445

- 810143172

- MSN在线咨询:
- upadv01@hotmail.com
- upadv05@hotmail.com
- upadv06@hotmail.com
|
|
文章内容
-
在正常执行脚本时,执行这些模块中定义的函数可能只需要使用 10% 甚至 5% 的时间。因此为什么不在启动脚本时加载这些模块呢?解决方案是使用 AutoLoader,其作用类似于 Perl 模块的动态加载程序。它使用了 AutoSplit 系统生成的文件,可以将一个模块划分成单个函数。当通过 use 加载模块时,要做的工作是加载该模块的 stub 代码。只有在调用 AutoLoader 加载的模块中包含的函数、然后为该函数加载并编译代码时,才会执行这项操作。结果是,把加载了模块的 20,000 个行的脚本又转换回 200 行的脚本,这将加速最初的加载和编译过程。
只是在程序中使用 AutoLoader 系统来代替预加载,就可以节省 2 秒钟的时间。这种方法很容易使用,只需将清单 8 所示的模块修改为清单 9 的格式,然后使用 AutoSplit 来创建需要的加载函数即可。注意,并不需要再使用 Exporter;AutoLoader 会自动处理加载单个函数的过程,而不用您显式地将其列出。
清单 8. 标准模块 package MyModule; use OtherModule; require 'Exporter'; @EXPORT = qw/MySub/; sub MySub { ... } 1;
清单 9. 自动加载模块 package MyModule; use OtherModule; use AutoLoader 'AUTOLOAD'; 1; __END__ sub MySub { ... }
这里的主要区别是,您希望自动加载的函数不再是在模块的包中定义,而是在模块末尾的数据段(在 __END__ 标志之后)定义。AutoSplit 会将在此处定义的所有函数放到特殊的 AutoLoader 文件中。要分割该模块,需要使用下面的命令行:
perl -e 'use AutoSplit; autosplit($ARGV[0], $ARGV[1], 0, 1, 1)' MyModule.pm auto
使用字节码和编译器后端 使用编译器有三种方法:字节码、完全编译或简单地作为一个调试/优化工具。前两种方法依赖于将原来的 Perl 源代码转换为编译好的字节码格式,并存储预编译的版本,以便以后执行。最好是通过 perlcc 命令使用这种方法。这两种模式使用相同的基本模型,但是产生的最终结果不同。在字节码的模式中,最终编译好的字节码被写入另外一个 Perl 脚本中。该脚本由 ByteLoader 前同步码组成,编译好的代码以字节字符串的形式保存。要创建字节码的格式,请在 perlcc 命令中使用 -B 选项。如下所示:
$ perlcc -B script.pl
这会创建一个文件 a.out。然而,输出结果的 Web 界面并不友好。结果文件可以在任何平台上作为 Perl 可执行程序执行(Perl 字节码是与平台无关的):
$ perl a.out
这样做的优点是节省了 Perl 每次将脚本从源代码编译成字节代码的时间。相反,它只运行生成的字节码。这与 Java 编译的过程类似,实际上与任何语言的真正编译步骤相同。在短小的脚本中,特别是哪些使用了很多外部模块的脚本中,您可能不会注意到速度有很大的提升。在大型的没有使用外部模块的“独立”脚本中,您应该会看到速度有明显的提升。
完全编译模式差不多也是这样,除了它会产生一个 Perl 脚本,其中嵌入了一些编译好的字节码。perlcc 会产生一些嵌入 C 代码的版本,然后将其编译成完全独立的可执行代码。虽然这个代码不是跨平台兼容的,但是它允许您分发一个 Perl 的可执行脚本,而不会泄漏出源代码。然而,需要注意的是,它并没有将 Perl 代码转换为 C 代码,只是将 Perl 字节码嵌入一个基于 C 的应用程序中。这实际上是 perlcc 的默认格式,因此,一个简单的 $ perlcc script.pl 会创建并编译一个独立的程序 a.out。
更少为人知的一种调试和优化代码的方法是,在 Perl 编译器中使用 "编译器后端"。
实际上是编译器后端驱动了 perlcc 命令,该命令可以使用一个后端模块直接创建一个 C 源代码文件,您可以查看该文件的内容。Perl 编译器通过使用所生成的字节码,以一种不同的方式输出结果。因为您正在查找在编译过程中生成的字节码,所以可以看到代码经过 Perl 自己内部优化后的结果。了解 Perl 的操作码,就可以开始判断哪里可能是瓶颈。从调试的观点来看,可以使用后端,例如 Terse (它自己就是 Concise 中的一个程序)和 Showlex。在清单 10 中,可以看到原来的清单 1 经过 Terse 后端处理后的样子。
清单 10. 使用 Terse 研究字节码 LISTOP (0x306230) leave [1] OP (0x305f60) enter COP (0x3062d0) nextstate BINOP (0x306210) sassign SVOP (0x301ab0) const [7] PV (0x1809f9c) "abcdefghijklmnopqrstuvwxyz" OP (0x305c30) padsv [1] COP (0x305c70) nextstate BINOP (0x305c50) sassign SVOP (0x306330) const [8] PV (0x180be60) "" OP (0x306310) padsv [2] COP (0x305f20) nextstate BINOP (0x305f00) leaveloop LOOP (0x305d10) enteriter [3] OP (0x305cf0) null [3] UNOP (0x305cd0) null [141] OP (0x305e80) pushmark SVOP (0x3065d0) const [9] IV (0x180be30) 1 SVOP (0x3065f0) const [10] IV (0x1801240) 999999 UNOP (0x305ee0) null LOGOP (0x305ec0) and OP (0x305d50) iter LISTOP (0x305e60) lineseq COP (0x305e10) nextstate BINOP (0x305df0) concat [6] OP (0x305d70) padsv [2] OP (0x305dd0) padsv [1] OP (0x305ea0) unstack concat1.pl syntax OK
其他工具 我们已经介绍的内容全部都是针对组成应用程序的代码的。虽然这是大部分问题之所在,但是还有一些工具和系统,可以用来帮助您判断和定位代码中最终有助于提高性能的一些问题。
warnings/strict 这是一个常见建议,但它们的确有所不同。使用 warnings 和 strict 标记可以确保不会出现可笑的变量使用、输入错误和其他问题。在脚本中使用这两个标记可以帮助您减少各种问题,其中很多都可能成为性能的瓶颈之源。这些标记引起的常见错误是:不正确的引用和取消引用,使用未定义的值,以及帮助判断输入错误,例如未使用的值或未定义的函数。
然而,所有这些帮助都可能会造成一些性能的损耗。我在编程和调试时保留了 warnings 和 strict,但在真正使用时,去掉了这些内容。这样不会节省太多时间,但能节省几毫秒的时间。
Profiling Profiling 是一个非常有用的优化代码的工具,但是它的作用是判断问题的位置;它并不能真正指出潜在的问题是什么,以及如何解决这些问题。而且,由于 profiling 依赖于监视应用程序不同部分的多次执行情况,所以有时候,对问题出在哪儿以及问题的解决方法,它会给出一些错误的建议。
然而,profiling 仍然非常有用,通常它都是优化过程的一个关键步骤。不要仅仅依靠它告诉您自己应该知道的所有内容。
调试 对于我来说,一个优化不好的程序就意味着该程序有 bug。反之亦然:bug 通常都会引起性能的问题。典型的例子是错误的取消引用变量,或者读取或过滤错误的信息。不用关心所用的调试技术使用的是 print 语句,还是 Perl 提供的完整调试器。越快消除这些 bug,就能越早开始优化程序。
使用所有的技术 现在您已经了解了一些技术,这里有一种方法可以使用这些这些技术生成优化的应用程序。在进行优化时,我通常遵循以下步骤: 1. 使用上面介绍的技术编写尽可能优化的程序。一旦开始有规律地使用这些技术,它们就会变成您进行编程的惟一方法。 2. 完成编程之后,或者在可以发布程序时,通读代码,再次手工检查程序,确定您使用的是可用的最有效解决方法。仅仅通过阅读代码,您就可以发现一些问题,还可能发现一些潜在的 bug。 3. 调试程序。bug 可能引起性能问题,因此,应该在进行优化之前首先消除 bug。 4. 运行 profiler。通常我要对重要的应用程序都执行一次这样的操作,只是为了看一下自己是否遗漏了什么内容 —— 显然一般都会遗漏点什么。 5. 回到步骤 1,重新开始。我忘记统计自己第一次忘记进行优化的次数了。我可能会反复这个过程 2 到 3 次,也可能离开做另外一个项目,然后在几天、几周或几个月后再回来进行优化。几周或几个月之后,您通常会发现实现相同功能而又可以节省时间的其他方法。
在每天日落时,并没有魔法杖可以帮助您优化软件。即使使用调试器和 profiler,您所获得的也只不过是一些简单的信息:什么可能导致了性能问题,以及有关应该如何修复这些问题的一些不太必要同时也不太有用的建议。还要注意的是,您可以优化的内容很有限。有些操作要花费很多时间才能完成。如果必须遍历一个 10,000 元素的 hash 表,那么就没有办法简化这个过程。但是,正如您已经看到的,有一些方法可以减少每种情况的开销。
点击:查看尚观ULP学员最新就业薪资待遇统计报告!
点击:了解尚观ULP-S专家课程(Linux主机、集群与大型数据库安全方向)
点击:了解尚观ULP-D专家课程(Linux内核、驱动与嵌入式开发方向)
填表获取 Linux、嵌入式、Oracle 技术资料
|