PHP前端开发中的性能那点事

PHP前端开发中的性能那点事

在我们平时的php开发中,一个大的项目经过长时间的积累以后你会发现性能越来越慢,而性能到底消耗在了什么地方,常常是一个令人头疼的问题,function a()调用了多少次,function b()又消耗了多少时间,我们到底怎么查找是哪个蛀虫拉慢了我们的程序运行速度呢?在这里给大家介绍一款工具xdebug,相信很多人已经听说过了,希望借助这个工具我们可以起到简单分析php程序性能瓶颈的问题。

A)假设1,假设用户目录在/home/ad

B)假设2,假设php目录在/home/ad/php

1、xdebug简介与安装

Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具),可以用来跟踪,调试和分析PHP程序的运行状况。

1)下载xdebug

xdebug的官方下载地址为:http://xdebug.org/download.php

最新版本为:Xdebug 2.1.0

2)xdebug的安装

1

2

3

4

5

6

7

8

cd /home/ad

wget http://xdebug.org/files/xdebug-2.1.0.tgz

tar -zxvf xdebug-2.1.0.tgz

cd xdebug-2.1.0

/home/ad/php/bin/phpize

./configure --enable-xdebug --with-php-config=/home/ad/php/bin/php-config

make

make install

安装完以后会提示你扩展安装到了哪个目录,类似 /home/ad/php/lib/php/extensions/no-debug-non-zts-20060613/

假设你的php.ini放在 /home/ad/php/lib/php.ini

加上

1

2

3

4

5

6

7

8

9

[xdebug]

zend_extension = "/home/ad/php/lib/php/extensions/no-debug-non-zts-20060613/xdebug.so"

xdebug.auto_trace = on

xdebug.auto_profile = on

xdebug.collect_params = on

xdebug.collect_return = on

xdebug.profiler_enable = on

xdebug.trace_output_dir = "/home/ad/xdebug_log"

xdebug.profiler_output_dir = "/home/ad/xdebug_log"

重启apache

去/home/ad/xdebug_log下看看是不是日志已经出来了

2、xdebug参数简介

zend_extension 加载xdebug扩展

xdebug.auto_trace 自动打开打开函数调用监测

xdebug.auto_profile 自动打开性能监测

xdebug.trace_output_dir 设定函数调用监测信息的输出文件的路径。

xdebug.profiler_output_dir 设定效能监测信息输出文件的路径。

xdebug.collect_params 打开收集“函数参数”的功能。将函数调用的参数值列入函数过程调用的监测信息中。

xdebug.collect_return 打开收集“函数返回值”的功能。将函数的返回值列入函数过程调用的监测信息中。

3、示例程序与日志收集

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<?php

function a()

{

echo "aaa";

}

function b()

{

a();

sleep(1);

a();

sleep(1);

a();

}

b();

?>

4、日志分析工具wincachegrind

http://sourceforge.net/projects/wincachegrind/

不用安装直接双击就可以打开了

我们用它打开刚才收集的日志cachegrind.out.***

前端开发中的性能那点事(二)巧用curl 并发减少后端访问时间

前言:

在我们平时的程序中难免出现同时访问几个接口的情况,平时我们用curl进行访问的时候,一般都是单个、顺序访问,假如有3个接口,每个接口耗时500毫秒那么我们三个接口就要花费1500毫秒了,这个问题太头疼了严重影响了页面访问速度,有没有可能并发访问来提高速度呢?今天就简单的说一下,利用curl并发来提高页面访问速度,

希望大家多指导。

1、老的curl访问方式以及耗时统计

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

<?php

function curl_fetch($url, $timeout=3){

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

$data = curl_exec($ch);

$errno = curl_errno($ch);

if ($errno>0) {

$data = false;

}

curl_close($ch);

return $data;

}

function microtime_float()

{

list($usec, $sec) = explode(" ", microtime());

return ((float)$usec + (float)$sec);

}

$url_arr=array(

"taobao"=>"http://www.taobao.com",

"sohu"=>"http://www.sohu.com",

"sina"=>"http://www.sina.com.cn",

);

$time_start = microtime_float();

$data=array();

foreach ($url_arr as $key=>$val)

{

$data[$key]=curl_fetch($val);

}

$time_end = microtime_float();

$time = $time_end - $time_start;

echo "耗时:{$time}";

?>

耗时:0.614秒

2、curl并发访问方式以及耗时统计

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

<?php

function curl_multi_fetch($urlarr=array()){

$result=$res=$ch=array();

$nch = 0;

$mh = curl_multi_init();

foreach ($urlarr as $nk => $url) {

$timeout=2;

$ch[$nch] = curl_init();

curl_setopt_array($ch[$nch], array(

CURLOPT_URL => $url,

CURLOPT_HEADER => false,

CURLOPT_RETURNTRANSFER => true,

CURLOPT_TIMEOUT => $timeout,

));

curl_multi_add_handle($mh, $ch[$nch]);

++$nch;

}

/* wait for performing request */

do {

$mrc = curl_multi_exec($mh, $running);

} while (CURLM_CALL_MULTI_PERFORM == $mrc);

while ($running && $mrc == CURLM_OK) {

// wait for network

if (curl_multi_select($mh, 0.5) > -1) {

// pull in new data;

do {

$mrc = curl_multi_exec($mh, $running);

} while (CURLM_CALL_MULTI_PERFORM == $mrc);

}

}

if ($mrc != CURLM_OK) {

error_log("CURL Data Error");

}

/* get data */

$nch = 0;

foreach ($urlarr as $moudle=>$node) {

if (($err = curl_error($ch[$nch])) == '') {

$res[$nch]=curl_multi_getcontent($ch[$nch]);

$result[$moudle]=$res[$nch];

}

else

{

error_log("curl error");

}

curl_multi_remove_handle($mh,$ch[$nch]);

curl_close($ch[$nch]);

++$nch;

}

curl_multi_close($mh);

return $result;

}

$url_arr=array(

"taobao"=>"http://www.taobao.com",

"sohu"=>"http://www.sohu.com",

"sina"=>"http://www.sina.com.cn",

);

function microtime_float()

{

list($usec, $sec) = explode(" ", microtime());

return ((float)$usec + (float)$sec);

}

$time_start = microtime_float();

$data=curl_multi_fetch($url_arr);

$time_end = microtime_float();

$time = $time_end - $time_start;

echo "耗时:{$time}";

?>

耗时:0.316秒

帅气吧整个页面访问后端接口的时间节省了一半

3、curl相关参数

来自:http://cn2.php.net/manual/en/ref.curl.php

curl_close — Close a cURL session

curl_copy_handle — Copy a cURL handle along with all of its preferences

curl_errno — Return the last error number

curl_error — Return a string containing the last error for the current session

curl_exec — Perform a cURL session

curl_getinfo — Get information regarding a specific transfer

curl_init — Initialize a cURL session

curl_multi_add_handle — Add a normal cURL handle to a cURL multi handle

curl_multi_close — Close a set of cURL handles

curl_multi_exec — Run the sub-connections of the current cURL handle

curl_multi_getcontent — Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set

curl_multi_info_read — Get information about the current transfers

curl_multi_init — Returns a new cURL multi handle

curl_multi_remove_handle — Remove a multi handle from a set of cURL handles

curl_multi_select — Wait for activity on any curl_multi connection

curl_setopt_array — Set multiple options for a cURL transfer

curl_setopt — Set an option for a cURL transfer

curl_version — Gets cURL version information

前端开发中的性能那点事(三)php的opcode缓存

前言:由php的运行机制决定,其实php在运行阶段我们也是可以进行缓存的从而提高程序运行效率,这就是我们常说的opcode缓存。

1、简述php的运行机制

(因为本文是写opcode缓存的所以这里只是简要概述,后边会专门写一篇揭秘php运行机制的。)

a).php文件通过浏览器过来

b)请求交给SAPI,随后SAPI层将控制权转给PHP

c)zend_language_scanner对代码进行扫描,对php代码进行词法分析转换成一系列的tokens array

d)zend_language_parser将c步骤产生的一系列tokens处理掉空格等无用的代码以后转换成一系列表达式

e)经过compiler阶段生成opcode返回zend_op_array指针

f)zend_vm_execute根据传入的zend_op_array指针,执行opcode并将结果返回输出

PHP前端开发中的性能那点事

2、opcode简介

Opcode是operation code(操作码)的简称,其实就是第一小节c)、d)、e)步骤产生的一种中间码,

opcode是一个四元组,(opcode, op1, op2, result),它们分别代表操作码,第一操作数,第二操作数,结果。

如:

1

2

3

<?php

echo "taobao search blog";

?>

对应的tokens

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

Array

(

[0] => Array

(

[0] => 367

[1] => <?php

[2] => 1

)

[1] => Array

(

[0] => 316

[1] => echo

[2] => 1

)

[2] => Array

(

[0] => 370

[1] =>

[2] => 1

)

[3] => Array

(

[0] => 315

[1] => "taobao search blog"

[2] => 1

)

[4] => ;

[5] => Array

(

[0] => 370

[1] =>

[2] => 1

)

[6] => Array

(

[0] => 369

[1] => ?>

[2] => 1

)

)

对应的opcode就是

1

2

3

4

5

line # * op fetch ext return operands

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

2 0 > ECHO 'taobao+search+blog'

4 1 > RETURN 1

2* > ZEND_HANDLE_EXCEPTION

3、使用apc对opcode缓存

a)假设php路径为/home/ad/php

对opcode进行缓存的软件很多(apc、eAcclerator、Xcache、Zend Platform),这里主要介绍apc

APC提供两种缓存功能,即缓存Opcode(目标文件),我们称之为apc_compiler_cache。同时它还提供一些接口用于PHP开发人员将用户数据驻留在内存中,我们称之为apc_user_cache。我们这里主要讨论apc_compiler_cache的配置。

下载地址:http://pecl.php.net/package/APC

最新版本为APC-3.1.6.tgz

1

2

3

4

5

6

7

wget http://pecl.php.net/get/APC-3.1.6.tgz

tar -zxvf APC-3.1.6.tgz

cd APC-3.1.6

/home/ad/php/bin/phpize

./configure --enable-apc --enable-apc-mmap --with-php-config=/home/ad/php/bin/php-config

make

make install

编辑php.ini

添加apc的配置

1

2

3

4

5

6

7

8

9

10

11

12

13

[apc]

extension=apc.so

apc.enabled=1

apc.shm_segments = 1

apc.shm_size = 128

apc.ttl = 0

apc.user_ttl = 7200

apc.num_files_hint = 1000

apc.write_lock=1

apc.stat = 0

apc.max_file_size=1M

apc.filters = a.php,b.php

apc.cache_by_default=1

重新apache就ok啦

4、常用参数的解析

apc.enabled 开启apc 设置为0关闭,1为开启

apc.shm_segments 共享内存块数

apc.shm_size 共享内存大小,但是是M

那么显然共享内存的总数就是apc.shm_segments*apc.shm_size

apc.num_files_hint 允许多少个opcode被缓存

apc.stat 为1的时候会自动检查opcode对应的php文件是否有更新,有更新的话会自动更新。设置为0的话就不会去检查了这样会提高apc的效率,但是要使php的修改生效的话就必须重启apache了,或者使用函数apc_cache_clear()来清空缓存

apc.ttl opcode缓存的过期时间,设置为0表示不过期,如果不为0会检查两次请求之间的时间,如果时间大于设置值那么会更新opcode缓存

apc.write_lock 表示多个进程同时更新一份opcode缓存的时候那么只让最先的一个生效,可以有效避免写冲突

apc.max_file_size 超过设置值大小的文件不被缓存

apc.filters 需要特例的文件,多个文件用逗号(,)相隔

apc.filters 与 apc.cache_by_default结合使用,

当apc.cache_by_default为1时apc.filters文件不被缓存,当apc.cache_by_default为0时仅apc.filters文件被缓存