PHP的array_pop多进程,php array_shift与array_pop执行速度差距为啥这么大

闲话不说,上问题:

一个很大的php数组(1w+),使用array_shfit跟array_pop取数组元素时,性能差距特别大,array_shift慢的无法忍受,而array_pop就很快了。

先不说答案,看段代码:

$arr = array(

0=>123,

3=>132,

2=>987,

);

array_shift($arr);

//array_pop($arr);

var_dump($arr);

输出会有什么不同呢,

array_shift后,输出为:

array(2) {

[0]=>

int(132)

[1]=>

int(987)

}

array_pop后,输出为:

array(2) {

[0]=>

int(123)

[3]=>

int(132)

}

有什么不同?

对,就是array_shift操作后,数组的键值变了。这就是array_shift为什么慢的原因了。因为array_shift操作数组会对数字键值,重新从0开始重建。每次移出一个元素后,就得遍历数组中的所有元素。array_pop就不会了。一个是O(1),一个是O(n)的复杂度,数组大了之后,效果就很明显了。

php里对应函数的C代码实现:

/* {{{ void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int off_the_end) */

static void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int off_the_end)

{

zval *stack,/* Input stack */

**val;/* Value to be popped */

char *key = NULL;

uint key_len = 0;

ulong index;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &stack) == FAILURE) {

return;

}

if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {

return;

}

/* Get the first or last value and copy it into the return value */

if (off_the_end) {

zend_hash_internal_pointer_end(Z_ARRVAL_P(stack));

} else {

zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));

}

zend_hash_get_current_data(Z_ARRVAL_P(stack), (void **)&val);

RETVAL_ZVAL(*val, 1, 0);

/* Delete the first or last value */

zend_hash_get_current_key_ex(Z_ARRVAL_P(stack), &key, &key_len, &index, 0, NULL);

if (key && Z_ARRVAL_P(stack) == &EG(symbol_table)) {

zend_delete_global_variable(key, key_len - 1 TSRMLS_CC);

} else {

zend_hash_del_key_or_index(Z_ARRVAL_P(stack), key, key_len, index, (key) ? HASH_DEL_KEY : HASH_DEL_INDEX);

}

//就是下面这里,遍历所有元素,对是数字键的元素重新赋值。pop的off_the_end是1,shift的off_the_end是0

/* If we did a shift... re-index like it did before */

if (!off_the_end) {

unsigned int k = 0;

int should_rehash = 0;

Bucket *p = Z_ARRVAL_P(stack)->pListHead;

while (p != NULL) {

if (p->nKeyLength == 0) {//键值是数字

if (p->h != k) {

p->h = k++;

should_rehash = 1;

} else {

k++;

}

}

p = p->pListNext;

}

Z_ARRVAL_P(stack)->nNextFreeElement = k;

if (should_rehash) {

//因为重新给键赋值,hash过后的位置可能不一样了,就得重新hash后,放到对应的位置。

zend_hash_rehash(Z_ARRVAL_P(stack));

}

} else if (!key_len && index >= Z_ARRVAL_P(stack)->nNextFreeElement - 1) {

Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1;

}

zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));

}

PHP_FUNCTION(array_pop)

{

_phpi_pop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);

}

PHP_FUNCTION(array_shift)

{

_phpi_pop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值