php array_shift與array_pop執行速度差距爲啥這麼大

閒話不說,上問題:php

一個很大的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後,輸出爲:ui

array(2) {spa

  [0]=>code

  int(132)element

  [1]=>get

  int(987)hash

}

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);
}
相關文章
相關標籤/搜索