菜单开关

周梦康 发表于 2019-04-16 38 次浏览 标签 : php

免费领取阿里云优惠券 我的直播 - 《PHP 进阶之路》

业务代码

$selectDate = [];

$first = explode("-", "");
$last = explode("-", "2019-04-16");

$minY = $first[0];
$minM = $first[1];
$maxY = $last[0];
$maxM = $last[1];
$n = 0;

for ($y = $minY; $y <= $maxY; $y++) {
    for ($m = 1; $m <= 12; $m++) {
        if ($y == $minY && $m < $minM) {
            continue;
        }

        if ($y == $maxY && $m > $maxM) {
            break 2;
        }
        $n++;
        array_unshift($selectDate, sprintf("%04d-%02d", $y, $m));
    }
}
echo $n."\n";

24232次循环。
PHP 5.4.32耗时39.930s(页面直接超时了);
PHP 5.6.40耗时6.550s;
PHP 7.2.14耗时3.319s;

strace 对比

服务器配置都是Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz 4核8G执行

strace -c php xx.php
# php 5.4.32
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 34.96    0.001530          22        71           brk
 31.92    0.001397          12       114           munmap
 18.90    0.000827          24        34        25 ioctl
 11.13    0.000487           2       242           mmap
  2.29    0.000100           1       119         7 open
  0.80    0.000035           0       115           close
  0.00    0.000000           0        94           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0        27         3 stat
  0.00    0.000000           0       143           fstat
  0.00    0.000000           0        14         8 lstat
  0.00    0.000000           0        29         3 lseek
  0.00    0.000000           0        81           mprotect
  0.00    0.000000           0         5           rt_sigaction
  0.00    0.000000           0         6           rt_sigprocmask
  0.00    0.000000           0         5         1 access
  0.00    0.000000           0         1           clone
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         3           fcntl
  0.00    0.000000           0         2           getdents
  0.00    0.000000           0         3           getcwd
  0.00    0.000000           0         4           gettimeofday
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         4           futex
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.004376                  1122        47 total
# php 5.6.40
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 49.38    0.000360           2       158           munmap
 21.26    0.000155           1       284           mmap
 17.83    0.000130           1       123         7 open
 11.52    0.000084           1       119           close
  0.00    0.000000           0        81           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0        30         2 stat
  0.00    0.000000           0       150           fstat
  0.00    0.000000           0        14         8 lstat
  0.00    0.000000           0        32         3 lseek
  0.00    0.000000           0        83           mprotect
  0.00    0.000000           0        24           brk
  0.00    0.000000           0         4           rt_sigaction
  0.00    0.000000           0         2           rt_sigprocmask
  0.00    0.000000           0        28        28 ioctl
  0.00    0.000000           0         3           access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         2           fcntl
  0.00    0.000000           0         4           getdents
  0.00    0.000000           0         3           getcwd
  0.00    0.000000           0         4           gettimeofday
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         4           futex
  0.00    0.000000           0         1           sched_setaffinity
  0.00    0.000000           0         2           sched_getaffinity
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.000729                  1161        48 total
# php 7.2.14
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 97.88    0.927258           5    193880           clock_gettime
  0.85    0.008041          34       240           mmap
  0.28    0.002688          19       138           mprotect
  0.22    0.002090          20       107         9 open
  0.17    0.001603          21        77           read
  0.16    0.001519          13       114           fstat
  0.15    0.001417          16        91           munmap
  0.13    0.001271          12       102           close
  0.05    0.000431         431         1           readlink
  0.03    0.000279           3        81           rt_sigaction
  0.02    0.000162           6        26           madvise
  0.02    0.000156           7        24         3 stat
  0.01    0.000066           3        22         3 lstat
  0.01    0.000051          26         2           futex
  0.01    0.000049           8         6         3 access
  0.00    0.000041           2        22         3 lseek
  0.00    0.000041          10         4           getcwd
  0.00    0.000033           2        15        15 mkdir
  0.00    0.000024          24         1           execve
  0.00    0.000022          11         2           write
  0.00    0.000022           1        35           brk
  0.00    0.000021           1        24           fcntl
  0.00    0.000020          20         1           arch_prctl
  0.00    0.000000           0         2           rt_sigprocmask
  0.00    0.000000           0        17        17 ioctl
  0.00    0.000000           0         2           getdents
  0.00    0.000000           0         1           unlink
  0.00    0.000000           0         1           fchmod
  0.00    0.000000           0         5           gettimeofday
  0.00    0.000000           0         2           getrlimit
  0.00    0.000000           0         2         2 statfs
  0.00    0.000000           0         1           gettid
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           openat
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.947305                195051        55 total

源码对比

/* PHP 5.4..32 */
PHP_FUNCTION(array_unshift)
{
    zval ***args,            /* Function arguments array */
           *stack;            /* Input stack */
    HashTable *new_hash;    /* New hashtable for the stack */
    HashTable  old_hash;
    int argc;                /* Number of function arguments */
    
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a+", &stack, &args, &argc) == FAILURE) {
        return;
    }

    /* Use splice to insert the elements at the beginning. Destroy old
     * hashtable and replace it with new one */
    new_hash = php_splice(Z_ARRVAL_P(stack), 0, 0, &args[0], argc, NULL);
    old_hash = *Z_ARRVAL_P(stack);
    if (Z_ARRVAL_P(stack) == &EG(symbol_table)) {
        zend_reset_all_cv(&EG(symbol_table) TSRMLS_CC);
    }
    *Z_ARRVAL_P(stack) = *new_hash;
    FREE_HASHTABLE(new_hash);
    zend_hash_destroy(&old_hash);

    /* Clean up and return the number of elements in the stack */
    efree(args);
    RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
}
/* PHP 5.6.40 */
PHP_FUNCTION(array_unshift)
{
    zval ***args,            /* Function arguments array */
           *stack;            /* Input stack */
    int argc;                /* Number of function arguments */
    
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a+", &stack, &args, &argc) == FAILURE) {
        return;
    }

    /* Use splice to insert the elements at the beginning. */
    php_splice(Z_ARRVAL_P(stack), 0, 0, args, argc, NULL TSRMLS_CC);

    /* Clean up and return the number of elements in the stack */
    efree(args);
    RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
}
/* PHP 7.2.14 */
PHP_FUNCTION(array_unshift)
{
    zval   *args,            /* Function arguments array */
           *stack;            /* Input stack */
    HashTable new_hash;        /* New hashtable for the stack */
    int argc;                /* Number of function arguments */
    int i;
    zend_string *key;
    zval *value;

    ZEND_PARSE_PARAMETERS_START(2, -1)
        Z_PARAM_ARRAY_EX(stack, 0, 1)
        Z_PARAM_VARIADIC('+', args, argc)
    ZEND_PARSE_PARAMETERS_END();

    zend_hash_init(&new_hash, zend_hash_num_elements(Z_ARRVAL_P(stack)) + argc, NULL, ZVAL_PTR_DTOR, 0);
    for (i = 0; i < argc; i++) {
        if (Z_REFCOUNTED(args[i])) {
            Z_ADDREF(args[i]);
        }
        zend_hash_next_index_insert_new(&new_hash, &args[i]);
    }
    if (EXPECTED(Z_ARRVAL_P(stack)->u.v.nIteratorsCount == 0)) {
        ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
            if (key) {
                zend_hash_add_new(&new_hash, key, value);
            } else {
                zend_hash_next_index_insert_new(&new_hash, value);
            }
        } ZEND_HASH_FOREACH_END();
    } else {
        uint32_t old_idx;
        uint32_t new_idx = i;
        uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);

        ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
            if (key) {
                zend_hash_add_new(&new_hash, key, value);
            } else {
                zend_hash_next_index_insert_new(&new_hash, value);
            }
            old_idx = (Bucket*)value - Z_ARRVAL_P(stack)->arData;
            if (old_idx == iter_pos) {
                zend_hash_iterators_update(Z_ARRVAL_P(stack), old_idx, new_idx);
                iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
            }
            new_idx++;
        } ZEND_HASH_FOREACH_END();
    }

    /* replace HashTable data */
    Z_ARRVAL_P(stack)->u.v.nIteratorsCount = 0;
    Z_ARRVAL_P(stack)->pDestructor = NULL;
    zend_hash_destroy(Z_ARRVAL_P(stack));

    Z_ARRVAL_P(stack)->u.v.flags         = new_hash.u.v.flags;
    Z_ARRVAL_P(stack)->nTableSize        = new_hash.nTableSize;
    Z_ARRVAL_P(stack)->nTableMask        = new_hash.nTableMask;
    Z_ARRVAL_P(stack)->nNumUsed          = new_hash.nNumUsed;
    Z_ARRVAL_P(stack)->nNumOfElements    = new_hash.nNumOfElements;
    Z_ARRVAL_P(stack)->nNextFreeElement  = new_hash.nNextFreeElement;
    Z_ARRVAL_P(stack)->arData            = new_hash.arData;
    Z_ARRVAL_P(stack)->pDestructor       = new_hash.pDestructor;

    zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));

    /* Clean up and return the number of elements in the stack */
    RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
}

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表