当前位置:  开发笔记 > 编程语言 > 正文

提升PHP性能之改变Zend引擎分发方式

从PHP5.1开始,PHP提供了用户对ZendVM执行分发方式的选择接口.之前的文章中,我也提过这方面的内容,Zend虚拟机在执行的时候,对于编译生成的op_array中的每一条opline的opcode都会分发到相应的处理...">

 

  从PHP5.1开始,PHP提供了用户对Zend VM执行分发方式的选择接口.

  之前的文章中, 我也提过这方面的内容, Zend虚拟机在执行的时候, 对于编译生成的op_array中的每一条opline的opcode都会分发到相应的处理器(zend_vm_def.h定义)执行, 而按照分发的方式不同, 分发过程可以分为CALL, SWITCH, 和GOTO三种类型.

  默认是CALL方式, 也就是所有的opcode处理器都定义为函数, 然后虚拟机调用. 这种方式是传统的方式, 也一般被认为是最稳定的方式.

  SWITCH方式和GOTO方式则和其命名的意义相同, 分别通过switch和goto来分发opcode到对应的处理逻辑(段).

  官方给出的描述是:

  CALL – Uses function handlers for opcodes

  SWITCH – Uses switch() statement for opcode dispatch

  GOTO – Uses goto for opcode dispatch (threaded opcodes architecture)

  GOTO is usually (depends on CPU and compiler) faster than SWITCH, which

  tends to be slightly faster than CALL.

  CALL is default because it doesn’t take very long to compile as opposed

  to the other two and in general the speed is quite close to the others.

  那么如果使用GOTO方式, 效率上到底能提高多少呢?

  今天我就分别使用各种方式来测试一番, 测试脚本bench.php.

  第一点被证明的就是, 官方说的GOTO方式编译耗时显著高于其他俩种方式, 我一开始在虚拟机上编译, 每次都Hangup(囧), 最后只好换了个强劲点的物理机, 大约3分钟后, 编译成功..

  测试环境:

 

  PHP 5.3.0 Linux

  AMD Opteron(tm) Processor 270(2G) X 4 6G Memory

 

  编译参数:

 

  ./configure --with-zend-vm=CALL/GOTO/SWITCH

 

  测试结果如下(都是三次取中值):

  CALL方式:

 

  laruence@dev01.tc$ sapi/cli/php bench.php

  simple 0.358

  simplecall 0.418

  simpleucall 0.405

  simpleudcall 0.424

  mandel 1.011

  mandel2 1.238

  ackermann(7) 0.375

  ary(50000) 0.083

  ary2(50000) 0.075

  ary3(2000) 0.561

  fibo(30) 1.156

  hash1(50000) 0.114

  hash2(500) 0.091

  heapsort(20000) 0.270

  matrix(20) 0.276

  nestedloop(12) 0.599

  sieve(30) 0.350

  strcat(200000) 0.039

  ------------------------

  Total 7.844

 

  SWITCH方式:

 

  laruence@dev01.tc$ sapi/cli/php bench.php

  simple 0.393

  simplecall 0.414

  simpleucall 0.424

  simpleudcall 0.445

  mandel 1.007

  mandel2 1.254

  ackermann(7) 0.392

  ary(50000) 0.084

  ary2(50000) 0.073

  ary3(2000) 0.593

  fibo(30) 1.185

  hash1(50000) 0.120

  hash2(500) 0.092

  heapsort(20000) 0.285

  matrix(20) 0.295

  nestedloop(12) 0.678

  sieve(30) 0.359

  strcat(200000) 0.042

  ------------------------

  Total 8.138

 

  GOTO方式 :

 

  laruence@dev01.tc$ sapi/cli/php bench.php

  simple 0.306

  simplecall 0.373

  simpleucall 0.369

  simpleudcall 0.385

  mandel 0.879

  mandel2 1.132

  ackermann(7) 0.356

  ary(50000) 0.081

  ary2(50000) 0.073

  ary3(2000) 0.525

  fibo(30) 1.043

  hash1(50000) 0.111

  hash2(500) 0.088

  heapsort(20000) 0.247

  matrix(20) 0.247

  nestedloop(12) 0.519

  sieve(30) 0.331

  strcat(200000) 0.037

  ------------------------

  Total 7.103

 

  可见, GOTO方式最快, SWITCH方式最慢.和官方的描述稍有不符.

  GOTO方式比其默认的CALL方式, 性能提升还是比较明显的.

  所以, 如果你希望让PHP发挥到机制, 改变Zend VM的分发方式, 也可以做为一个考虑因素.

  附:

  使用GOTO方式的configure选项:

 

  --with-zend-vm=GOTO

 

  也可以在Zend目录下使用:

 

  php zend_vm_gen.php --with-vm-kind=[CALL|GOTO|SWITH]

 

  测试脚本bench.php

 

  

  /**

  * PHP Perf Bench Test Script

  */

  function simple() {

  $a = 0;

  for ($i = 0; $i <1000000; $i++)

  $a++;

  $thisisanotherlOngname= 0;

  for ($thisisalOngname= 0; $thisisalongname <1000000; $thisisalongname++)

  $thisisanotherlongname++;

  }

  /****/

  function simplecall() {

  for ($i = 0; $i <1000000; $i++)

  strlen("hallo");

  }

  /****/

  function hallo($a) {

  }

  function simpleucall() {

  for ($i = 0; $i <1000000; $i++)

  hallo("hallo");

  }

  /****/

  function simpleudcall() {

  for ($i = 0; $i <1000000; $i++)

  hallo2("hallo");

  }

  function hallo2($a) {

  }

  /****/

  function mandel() {

  $w1=50;

  $h1=150;

  $recen=-.45;

  $imcen=0.0;

  $r=0.7;

  $s=0; $rec=0; $imc=0; $re=0; $im=0; $re2=0; $im2=0;

  $x=0; $y=0; $w2=0; $h2=0; $color=0;

  $s=2*$r/$w1;

  $w2=40;

  $h2=12;

  for ($y=0 ; $y<=$w1; $y=$y+1) {

  $imc=$s*($y-$h2)+$imcen;

  for ($x=0 ; $x<=$h1; $x=$x+1) {

  $rec=$s*($x-$w2)+$recen;

  $re=$rec;

  $im=$imc;

  $color=1000;

  $re2=$re*$re;

  $im2=$im*$im;

  while( ((($re2+$im2)<1000000) && $color>0)) {

  $im=$re*$im*2+$imc;

  $re=$re2-$im2+$rec;

  $re2=$re*$re;

  $im2=$im*$im;

  $color=$color-1;

  }

  if ( $color==0 ) {

  print "_";

  } else {

  print "#";

  }

  }

  print "
";

  flush();

  }

  }

  /****/

  function mandel2() {

  $b = " .:,;!/>)|&IH%*#";

  //float r, i, z, Z, t, c, C;

  for ($y=30; printf("\n"), $C = $y*0.1 - 1.5, $y--;){

  for ($x=0; $c = $x*0.04 - 2, $z=0, $Z=0, $x++ <75;){

  for ($r=$c, $i=$C, $k=0; $t = $z*$z - $Z*$Z + $r, $Z = 2*$z*$Z + $i, $z=$t, $k<5000; $k++)

  if ($z*$z + $Z*$Z > 500000) break;

  echo $b[$k%16];

  }

  }

  }

  /****/

  function Ack($m, $n){

  if($m == 0) return $n+1;

  if($n == 0) return Ack($m-1, 1);

  return Ack($m - 1, Ack($m, ($n - 1)));

  }

  function ackermann($n) {

  $r = Ack(3,$n);

  print "Ack(3,$n): $r\n";

  }

  /****/

  function ary($n) {

  for ($i=0; $i<$n; $i++) {

  $X[$i] = $i;

  }

  for ($i=$n-1; $i>=0; $i--) {

  $Y[$i] = $X[$i];

  }

  $last = $n-1;

  print "$Y[$last]\n";

  }

  /****/

  function ary2($n) {

  for ($i=0; $i<$n;) {

  $X[$i] = $i; ++$i;

  $X[$i] = $i; ++$i;

  $X[$i] = $i; ++$i;

  $X[$i] = $i; ++$i;

  $X[$i] = $i; ++$i;

  $X[$i] = $i; ++$i;

  $X[$i] = $i; ++$i;

  $X[$i] = $i; ++$i;

  $X[$i] = $i; ++$i;

  $X[$i] = $i; ++$i;

  }

  for ($i=$n-1; $i>=0;) {

  $Y[$i] = $X[$i]; --$i;

  $Y[$i] = $X[$i]; --$i;

  $Y[$i] = $X[$i]; --$i;

  $Y[$i] = $X[$i]; --$i;

  $Y[$i] = $X[$i]; --$i;

  $Y[$i] = $X[$i]; --$i;

  $Y[$i] = $X[$i]; --$i;

  $Y[$i] = $X[$i]; --$i;

  $Y[$i] = $X[$i]; --$i;

  $Y[$i] = $X[$i]; --$i;

  }

  $last = $n-1;

  print "$Y[$last]\n";

  }

  /****/

  function ary3($n) {

  for ($i=0; $i<$n; $i++) {

  $X[$i] = $i + 1;

  $Y[$i] = 0;

  }

  for ($k=0; $k<1000; $k++) {

  for ($i=$n-1; $i>=0; $i--) {

  $Y[$i] += $X[$i];

  }

  }

  $last = $n-1;

  print "$Y[0] $Y[$last]\n";

  }

  /****/

  function fibo_r($n){

  return(($n <2) ? 1 : fibo_r($n - 2) + fibo_r($n - 1));

  }

  function fibo($n) {

  $r = fibo_r($n);

  print "$r\n";

  }

  /****/

  function hash1($n) {

  for ($i = 1; $i <= $n; $i++) {

  $X[dechex($i)] = $i;

  }

  $c = 0;

  for ($i = $n; $i > 0; $i--) {

  if ($X[dechex($i)]) { $c++; }

  }

  print "$c\n";

  }

  /****/

  function hash2($n) {

  for ($i = 0; $i <$n; $i++) {

  $hash1["foo_$i"] = $i;

  $hash2["foo_$i"] = 0;

  }

  for ($i = $n; $i > 0; $i--) {

  foreach($hash1 as $key => $value) $hash2[$key] += $value;

  }

  $first = "foo_0";

  $last = "foo_".($n-1);

  print "$hash1[$first] $hash1[$last] $hash2[$first] $hash2[$last]\n";

  }

  /****/

  function gen_random ($n) {

  global $LAST;

  return( ($n * ($LAST = ($LAST * IA + IC) % IM)) / IM );

  }

  function heapsort_r($n, &$ra) {

  $l = ($n >> 1) + 1;

  $ir = $n;

  while (1) {

  if ($l > 1) {

  $rra = $ra[--$l];

  } else {

  $rra = $ra[$ir];

  $ra[$ir] = $ra[1];

  if (--$ir == 1) {

  $ra[1] = $rra;

  return;

  }

  }

  $i = $l;

  $j = $l <<1;

  while ($j <= $ir) {

  if (($j <$ir) && ($ra[$j] <$ra[$j+1])) {

  $j++;

  }

  if ($rra <$ra[$j]) {

  $ra[$i] = $ra[$j];

  $j += ($i = $j);

  } else {

  $j = $ir + 1;

  }

  }

  $ra[$i] = $rra;

  }

  }

  function heapsort($N) {

  global $LAST;

  define("IM", 139968);

  define("IA", 3877);

  define("IC", 29573);

  $LAST = 42;

  for ($i=1; $i<=$N; $i++) {

  $ary[$i] = gen_random(1);

  }

  heapsort_r($N, $ary);

  printf("%.10f\n", $ary[$N]);

  }

  /****/

  function mkmatrix ($rows, $cols) {

  $count = 1;

  $mx = array();

  for ($i=0; $i<$rows; $i++) {

  for ($j=0; $j<$cols; $j++) {

  $mx[$i][$j] = $count++;

  }

  }

  return($mx);

  }

  function mmult ($rows, $cols, $m1, $m2) {

  $m3 = array();

  for ($i=0; $i<$rows; $i++) {

  for ($j=0; $j<$cols; $j++) {

  $x = 0;

  for ($k=0; $k<$cols; $k++) {

  $x += $m1[$i][$k] * $m2[$k][$j];

  }

  $m3[$i][$j] = $x;

  }

  }

  return($m3);

  }

  function matrix($n) {

  $SIZE = 30;

  $m1 = mkmatrix($SIZE, $SIZE);

  $m2 = mkmatrix($SIZE, $SIZE);

  while ($n--) {

  $mm = mmult($SIZE, $SIZE, $m1, $m2);

  }

  print "{$mm[0][0]} {$mm[2][3]} {$mm[3][2]} {$mm[4][4]}\n";

  }

  /****/

  function nestedloop($n) {

  $x = 0;

  for ($a=0; $a<$n; $a++)

  for ($b=0; $b<$n; $b++)

  for ($c=0; $c<$n; $c++)

  for ($d=0; $d<$n; $d++)

  for ($e=0; $e<$n; $e++)

  for ($f=0; $f<$n; $f++)

  $x++;

  print "$x\n";

  }

  /****/

  function sieve($n) {

  $count = 0;

  while ($n-- > 0) {

  $count = 0;

  $flags = range (0,8192);

  for ($i=2; $i<8193; $i++) {

  if ($flags[$i] > 0) {

  for ($k=$i+$i; $k <= 8192; $k+=$i) {

  $flags[$k] = 0;

  }

  $count++;

  }

  }

  }

  print "Count: $count\n";

  }

  /****/

  function strcat($n) {

  $str = "";

  while ($n-- > 0) {

  $str .= "hello\n";

  }

  $len = strlen($str);

  print "$len\n";

  }

  /*****/

  function getmicrotime()

  {

  $t = gettimeofday();

  return ($t[&#39;sec&#39;] + $t[&#39;usec&#39;] / 1000000);

  }

  function start_test()

  {

  ob_start();

  return getmicrotime();

  }

  function end_test($start, $name)

  {

  global $total;

  $end = getmicrotime();

  ob_end_clean();

  $total += $end-$start;

  $num = number_format($end-$start,3);

  $pad = str_repeat(" ", 24-strlen($name)-strlen($num));

  echo $name.$pad.$num."\n";

  ob_start();

  return getmicrotime();

  }

  function total()

  {

  global $total;

  $pad = str_repeat("-", 24);

  echo $pad."\n";

  $num = number_format($total,3);

  $pad = str_repeat(" ", 24-strlen("Total")-strlen($num));

  echo "Total".$pad.$num."\n";

  }

  $t0 = $t = start_test();

  simple();

  $t = end_test($t, "simple");

  simplecall();

  $t = end_test($t, "simplecall");

  simpleucall();

  $t = end_test($t, "simpleucall");

  simpleudcall();

  $t = end_test($t, "simpleudcall");

  mandel();

  $t = end_test($t, "mandel");

  mandel2();

  $t = end_test($t, "mandel2");

  ackermann(7);

  $t = end_test($t, "ackermann(7)");

  ary(50000);

  $t = end_test($t, "ary(50000)");

  ary2(50000);

  $t = end_test($t, "ary2(50000)");

  ary3(2000);

  $t = end_test($t, "ary3(2000)");

  fibo(30);

  $t = end_test($t, "fibo(30)");

  hash1(50000);

  $t = end_test($t, "hash1(50000)");

  hash2(500);

  $t = end_test($t, "hash2(500)");

  heapsort(20000);

  $t = end_test($t, "heapsort(20000)");

  matrix(20);

  $t = end_test($t, "matrix(20)");

  nestedloop(12);

  $t = end_test($t, "nestedloop(12)");

  sieve(30);

  $t = end_test($t, "sieve(30)");

  strcat(200000);

  $t = end_test($t, "strcat(200000)");

  total($t0, "Total");

  ?>


推荐阅读
  • 大数据应用实例:电视收视率分析企业项目实操第二篇
    本文继续探讨大数据在电视收视率分析中的应用,详细介绍了如何在CentOS系统中进行防火墙管理。针对CentOS 6.5及更早版本,提供了具体的命令操作步骤,包括停止防火墙服务和禁用防火墙启动。此外,还深入讨论了这些操作对数据传输和系统安全的影响,为实际项目实施提供了宝贵的技术参考。 ... [详细]
  • 为了在Fragment中直接调用Activity的方法,可以通过定义一个接口并让Activity实现该接口来实现。具体步骤包括:首先在Fragment中声明一个接口,并在Activity中实现该接口。接着,在Fragment中通过类型转换检查Activity是否实现了该接口,如果实现了则调用相应的方法。这种方法不仅提高了代码的解耦性,还增强了模块间的通信效率。此外,还可以通过ViewModel或LiveData等现代Android架构组件进一步优化这一过程,以实现更加高效和可靠的通信机制。 ... [详细]
  • 基于Node.js的高性能实时消息推送系统通过集成Socket.IO和Express框架,实现了高效的高并发消息转发功能。该系统能够支持大量用户同时在线,并确保消息的实时性和可靠性,适用于需要即时通信的应用场景。 ... [详细]
  • 在Linux环境下,本文详细探讨了Apache服务器中CGI技术的应用与实现。首先,通过使用yum包管理器安装了必要的软件,如PHP。安装完成后,对Apache服务器进行了配置,确保CGI功能正常运行。此外,还介绍了如何编写和调试CGI脚本,以及如何在实际环境中部署这些脚本以提供动态网页内容。实验结果表明,通过合理的配置和优化,Apache服务器能够高效地支持CGI应用程序,为用户提供丰富的交互体验。 ... [详细]
  • 本文深入解析了 Apache 配置文件 `httpd.conf` 和 `.htaccess` 的优化方法,探讨了如何通过合理配置提升服务器性能和安全性。文章详细介绍了这两个文件的关键参数及其作用,并提供了实际应用中的最佳实践,帮助读者更好地理解和运用 Apache 配置。 ... [详细]
  • 本文作为“实现简易版Spring系列”的第五篇,继前文深入探讨了Spring框架的核心技术之一——控制反转(IoC)之后,将重点转向另一个关键技术——面向切面编程(AOP)。对于使用Spring框架进行开发的开发者来说,AOP是一个不可或缺的概念。了解AOP的背景及其基本原理,对于掌握这一技术至关重要。本文将通过具体示例,详细解析AOP的实现机制,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 本文首先对信息漏洞的基础知识进行了概述,重点介绍了几种常见的信息泄露途径。具体包括目录遍历、PHPINFO信息泄露以及备份文件的不当下载。其中,备份文件下载涉及网站源代码、`.bak`文件、Vim缓存文件和`DS_Store`文件等。目录遍历漏洞的详细分析为后续深入研究奠定了基础。 ... [详细]
  • 微信支付授权目录配置详解及操作步骤
    在使用微信支付时,若通过WeixinJSBridge.invoke方法调用支付功能,可能会遇到“当前页面URL未注册”的错误提示,导致get_brand_wcpay_request:fail调用微信JSAPI支付失败。为解决这一问题,需要正确配置微信支付授权目录,确保支付页面的URL已成功注册。本文将详细介绍微信支付授权目录的配置步骤和注意事项,帮助开发者顺利完成支付功能的集成与调试。 ... [详细]
  • 如何将PHP文件上传至服务器及正确配置服务器地址 ... [详细]
  • Ceph API微服务实现RBD块设备的高效创建与安全删除
    本文旨在实现Ceph块存储中RBD块设备的高效创建与安全删除功能。开发环境为CentOS 7,使用 IntelliJ IDEA 进行开发。首先介绍了 librbd 的基本概念及其在 Ceph 中的作用,随后详细描述了项目 Gradle 配置的优化过程,确保了开发环境的稳定性和兼容性。通过这一系列步骤,我们成功实现了 RBD 块设备的快速创建与安全删除,提升了系统的整体性能和可靠性。 ... [详细]
  • 如何在Linux系统中利用crontab定时执行Shell脚本任务?
    在Linux系统中,如何实现定时执行任务脚本?在服务器日常运维过程中,经常需要定期执行某些任务,例如数据库备份、日志文件切割等。通过使用crontab工具,可以轻松配置这些周期性任务,确保它们按时自动运行,提高系统管理效率和可靠性。 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • Storm学习心得:深入探讨消息可靠传输与一致性事务处理
    在本文中,我们深入探讨了Storm框架在消息可靠传输与一致性事务处理方面的核心机制。通过对消息处理流程的详细分析,结合实际案例,阐述了如何确保数据在分布式环境中的一致性和可靠性。此外,还介绍了Storm中的事务拓扑设计及其在高并发场景下的应用,为开发者提供了宝贵的实践经验和优化建议。 ... [详细]
  • 超分辨率技术的全球研究进展与应用现状综述
    本文综述了图像超分辨率(Super-Resolution, SR)技术在全球范围内的最新研究进展及其应用现状。超分辨率技术旨在从单幅或多幅低分辨率(Low-Resolution, LR)图像中恢复出高质量的高分辨率(High-Resolution, HR)图像。该技术在遥感、医疗成像、视频处理等多个领域展现出广泛的应用前景。文章详细分析了当前主流的超分辨率算法,包括基于传统方法和深度学习的方法,并探讨了其在实际应用中的优缺点及未来发展方向。 ... [详细]
  • 在主从复制架构中,Bingo_MySQL 同步工具的应用与优化具有重要意义。为确保高效同步,建议使用相同或兼容的 MySQL 版本,并确保两台服务器位于同一局域网内,且网络连接畅通无阻。若无法 ping 通,请检查 IP 配置及防火墙设置,以保证网络连通性。此外,合理的配置参数和定期维护也是提升同步性能的关键因素。 ... [详细]
author-avatar
士贤俊宪秀珍
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有