1. 云栖社区>
  2. PHP教程>
  3. 正文

PHP官方的pcntl_signal性能极差

作者:用户 来源:互联网 时间:2017-12-01 17:10:06

开发

PHP官方的pcntl_signal性能极差 - 摘要: 本文讲的是PHP官方的pcntl_signal性能极差, 很多纯PHP开发的后端框架中都使用了pcntl扩展提供的信号处理函数pcntl_signal,实际上这个函数的性能是很差的。首先看一段示例代码: declare(ticks = 1);pcntl_signal(SIGINT, 'signa

很多纯PHP开发的后端框架中都使用了pcntl扩展提供的信号处理函数pcntl_signal,实际上这个函数的性能是很差的。首先看一段示例代码:

declare(ticks = 1);pcntl_signal(SIGINT, 'signalHandler');

这段代码在执行pcntl_signal前,先加入了declare(ticks = 1)。因为PHP的函数无法直接注册到操作系统信号设置中,所以pcntl信号需要依赖tick机制。通过查看pcntl.c的源码实现发现。pcntl_signal的实现原理是,触发信号后先将信号加入一个队列中。然后在PHP的ticks回调函数中不断检查是否有信号,如果有信号就执行PHP中指定的回调函数,如果没有则跳出函数。

PHP_MINIT_FUNCTION(pcntl){	php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);	php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);	php_add_tick_function(pcntl_signal_dispatch TSRMLS_CC);	return SUCCESS;}

pcntl_signal_dispatch 函数的实现:

void pcntl_signal_dispatch(){	//.... 这里略去一部分代码,queue即是信号队列	while (queue) {		if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {			ZVAL_NULL(&retval);			ZVAL_LONG(&param, queue->signo);			/* Call php signal handler - Note that we do not report errors, and we ignore the return value */			/* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */			call_user_function(EG(function_table), NULL, handle, &retval, 1, &param TSRMLS_CC);			zval_ptr_dtor(&param);			zval_ptr_dtor(&retval);		}		next = queue->next;		queue->next = PCNTL_G(spares);		PCNTL_G(spares) = queue;		queue = next;	}}

这样就存在一个比较严重的性能问题,大家都知道PHP的ticks=1表示每执行1行PHP代码就回调此函数。实际上大部分时间都没有信号产生,但ticks的函数一直会执行。如果一个服务器程序1秒中接收1000次请求,平均每个请求要执行1000行PHP代码。那么PHP的pcntl_signal,就带来了额外的 1000 * 1000,也就是100万次空的函数调用。这样会浪费大量的CPU资源。

比较好的做法是去掉ticks,转而使用pcntl_signal_dispatch,在代码循环中自行处理信号。而swoole中因为底层是C实现的,信号处理不受PHP的影响。swoole使用了目前Linux系统中最先进的signalfd来处理信号,几乎是没有任何额外消耗的。

以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索开发 ,以便于您获取更多的相关知识。