ZendFramework官方提供的性能优化没有实际意义

来源:互联网 发布:淘宝网小衫女 编辑:程序博客网 时间:2024/06/06 06:24

昨天把zf的官方性能优化都做了一遍,本来希望官方的性能优化方案能够真正起到优化效果,中间由于bug误以为有效果了,还发了一篇博文,可惜后来一查完全越优化越差了。下面简单吧ZF官方的性能优化说一下,还有最新的(ZF1版,第二版还没有怎么用)ZF1.12中添加的autoload_classmap的机制,设计cache的部分就不提了,那个减少了代码的执行逻辑,性能提升是肯定的(还需要对比缓存获取过程和减少的代码逻辑执行的时间差,提升不绝对)。

官方优化如下:

1、在include_path的路径中使用绝对路径,这样可以使用php的realpath cache
While this may seem a micro-optimization, the fact is that if you don't, you'll get very little benefit from PHP's realpath cache, and as a result, opcode caching will not perform nearly as you may expect.

2、减少include_path的路径定义,定义ZF在include_path的前面,将当前目录放在最后或者不使用当前目录,这样可以加快文件查找的速度。

Include paths are scanned in the order in which they appear in the include_path. Obviously, this means that you'll get a result faster if the file is found on the first scan rather than the last. Thus, a rather obvious enhancement is to simply reduce the number of paths in your include_path to only what you need. Look through each include_path you've defined, and determine if you actually have any functionality in that path that is used in your application; if not, remove it.

目的是为了加快文件查找过程,觉得这点不够好,最好是所有文件都使用绝对地址加载不要查找,浪费这个时间做什么啊

3、减少不需要的require_once,完全使用autoload和require加载,官方提供了一个shell来删除require_once
  1. % cd path/to/ZendFramework/library
  2. % find . -name '*.php' -not -wholename '*/Loader/Autoloader.php' \
  3.   -not -wholename '*/Application.php' -print0 | \
  4.   xargs -0 sed --regexp-extended --in-place 's/(require_once)/\/\/ \1/g'
这个效果还是比较明显的,要求你写程序要符合规范要让加载器能够找到你的文件并加载,要不然你就麻烦了。
另外,最好都使用require或include,不要加once,原因看http://www.laruence.com/2012/09/12/2765.html; 
使用apc的用户,在产品上线后可以把apc的stat设置为0,不让它检查文件修改,这样也可以获得性能提升,更新文件可以自己写程序清理下缓存

4、加快插件加载,使用一个include文件将常用插件放在文件中
个人感觉这个行为的过程就是把每次单独加载的过程改成一次完成,然后依靠apc等缓存来提速,这个的作用真不明显

5、使用自动加载器Zend_Loader_ClassMapAutoloader
这个确实没有怎么感觉到提升,个人认为即使加了这个也不能解决ZF过于臃肿的问题,优化本身就有限制。
这里给个添加的方法,有兴趣的朋友可以试试,以下部分内容来自上次误写的一篇博文。

加载器的使用:
在ZF1.12的目录中有一个bin目录下面有加载器类需要的classmap文件创建程序classmap_generator.php,通过这个创建器我们可以对相应目录下的类进行classmap文件生成,生成文件默认是在指定的class目录下的,也就是说都是基于你给创建器指定的目录的,也可以通过-o or --output 来指定。

在进行生成classmap生成前最好看下创建器的帮助,使用php classmap_generator.php -h,打印有如下信息:
Usage: classmap_generator.php [ options ]
--help|-h                 Get usage message
--library|-l [ <string> ] Library to parse; if none provided, assumes current directory
--output|-o [ <string> ]  Where to write autoload file; if not provided, assumes "autoload_classmap.php" in library directory
--overwrite|-w            Whether or not to overwrite existing autoload file

然后就可以使用,例如:php  classmap_generator.php -l /data/www/library,  执行完就可以看到映射文件了。
接下来就要使用加载器了,可以看到Zend_Loader_ClassMapAutoloader文件里面提供了register,autoload方法,通过这个方法可以直接使用加载器,提醒,这里需要一个前提,如果你先前没有使用其他加载器,这里可以直接使用,如果先前有使用,比如我自己就一直使用Zend_Loader_Autoloader,并注册了一些命名空间,这样使用的时候就会有问题,如果映射文件包含所有加载的类,可以去掉原来的加载器直接使用,如果不是这样,保险起见可以把类映射加载器作为Zend_Loader_Autoloader的一个回调就好了,如下:
require_once LIB_DIR . 'Zend/Loader/ClassMapAutoloader.php';
$loader_map = new Zend_Loader_ClassMapAutoloader();
$loader_map->registerAutoloadMaps( array(LIB_DIR . 'autoload_classmap.php' , APP_DIR . 'models' . DIRECTORY_SEPARATOR . 'autoload_classmap.php' ));

require_once LIB_DIR . 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->unshiftAutoloader(array($loader_map, 'autoload' ));
然后把注册的命名空间去掉,就可以使用了。

测试下效果
硬件环境
CPU: Intel(R) Xeon(R) CPU   E5620
mem:  4G used 2.4 free 1.3

软件环境
nginx 1.2.4 php 5.3.17

不使用类加载器:
Concurrency Level:      40
Time taken for tests:   0.811 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      449700 bytes
HTML transferred:       437600 bytes
Requests per second:    123.29 [#/sec] (mean)
Time per request:       324.432 [ms] (mean)
Time per request:       8.111 [ms] (mean, across all concurrent requests)
Transfer rate:          541.45 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   1.4      2      14
Processing:    47  253  81.3    280     343
Waiting:       44  253  81.4    280     343
Total:         48  255  81.2    282     344

Percentage of the requests served within a certain time (ms)
  50%    282
  66%    292
  75%    308
  80%    318
  90%    333
  95%    336
  98%    344
  99%    344
100%    344 (longest request)

使用大文件(72K)同时使用类加载器:
Concurrency Level:      40
Time taken for tests:   0.831 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      449700 bytes
HTML transferred:       437600 bytes
Requests per second:    120.32 [#/sec] (mean)
Time per request:       332.433 [ms] (mean)
Time per request:       8.311 [ms] (mean, across all concurrent requests)
Transfer rate:          528.42 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.5      1      15
Processing:    46  258  79.0    300     334
Waiting:       45  258  79.0    299     334
Total:         48  260  78.9    301     335

Percentage of the requests served within a certain time (ms)
  50%    301
  66%    307
  75%    311
  80%    313
  90%    314
  95%    322
  98%    330
  99%    335
100%    335 (longest request)

可以看到和原来情况差不多,究其原因,个人通过跟踪php-fpm的进程过程,发现文件本身的加载在ZF中已经达到160个文件以上了,这个classmap不能减少这个操作,只能说是应用了官方优化的第一条,这个不能解决框架本身的性能瓶颈。对比下yii包含的文件数60个,这个就是性能差距的根本。

资料:
http://talks.php.net/show/froscon08/0
http://framework.zend.com/manual/1.12/en/performance.html
http://yiiframework.com/