Почему date () работает вдвое быстрее, если мы устанавливаем часовой пояс из кода? - PullRequest
32 голосов
/ 05 апреля 2011

Замечали ли вы, что функция date() работает * на 1002 * в 2 раза быстрее , чем обычно, если вы устанавливаете фактический часовой пояс внутри скрипта перед любым вызовом date()? Мне очень любопытно по этому поводу.

Посмотрите на этот простой кусок кода:

<?php

  $start = microtime(true);
  for ($i = 0; $i < 100000; $i++) date('Y-m-d H:i:s');
  echo (microtime(true) - $start);

?>

Он просто вызывает функцию date(), используя цикл for 100 000 раз. Результат, который я получаю, всегда составляет около 1,6 секунды (Windows, PHP 5.3.5), но…

Если я снова установлю тот же часовой пояс, добавив одну абсурдную строку перед запуском:

date_default_timezone_set(date_default_timezone_get());

Я получаю время ниже 800 мс ; ~ В 2 раза быстрее (тот же сервер).

Я искал какое-то разумное объяснение этому поведению, но безуспешно. С моей точки зрения, эта дополнительная строка бесполезна, но PHP не согласен со мной.

Я попробовал этот тест на двух серверах Linux (разные версии PHP) и получил разное время, но в пропорции ~ 6: 1 .

Примечание: date.timezone свойство в php.ini установлено правильно (Европа / Париж).

Я искал похожие вопросы здесь и не нашел ничего похожего. Я также проверил руководство для date_default_time_zone () function @ php.net и обнаружил, что я не единственный, кто это заметил, но все еще не может понять, почему это происходит?

Любой

Ответы [ 2 ]

41 голосов
/ 05 апреля 2011

Обновление для PHP 5.4:

Как описано в описании date_default_timezone_get, начиная с PHP 5.4.0, алгоритм для определения часового пояса по системной информации былудален из кода (в отличие от источника PHP 5.3), так что это поведение больше не существует.

Запустив тест синхронизации на моем сервере разработки, чтобы увидеть его в действии, я получил:

  • PHP 5.3.11: ~ 720 мс
  • PHP 5.4.3: ~ 470 мс

Оригинальный ответ:

Я только что посмотрел на исходный код PHP,В частности, весь соответствующий код находится в /ext/date/php_date.c.

. Я начал с предположения, что если вы не предоставите часовой пояс для date, вызывается date_default_timezone_get, чтобы получить его., Вот эта функция :

PHP_FUNCTION(date_default_timezone_get)
{
    timelib_tzinfo *default_tz;

    default_tz = get_timezone_info(TSRMLS_C);
    RETVAL_STRING(default_tz->name, 1);
}

ОК, так как же выглядит get_timezone_info? Это :

PHPAPI timelib_tzinfo *get_timezone_info(TSRMLS_D)
{
    char *tz;
    timelib_tzinfo *tzi;

    tz = guess_timezone(DATE_TIMEZONEDB TSRMLS_CC);
    tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
    if (! tzi) {
        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
    }
    return tzi;
}

А как же guess_timezone? Здесь это:

static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC)
{
    char *env;

    /* Checking configure timezone */
    if (DATEG(timezone) && (strlen(DATEG(timezone)) > 0)) {
        return DATEG(timezone);
    }
    /* Check environment variable */
    env = getenv("TZ");
    if (env && *env && timelib_timezone_id_is_valid(env, tzdb)) {
        return env;
    }
    /* Check config setting for default timezone */
    /*  ..... code omitted ....... */
#if HAVE_TM_ZONE
    /* Try to guess timezone from system information */
    /*  ..... code omitted ....... */
#endif
#ifdef PHP_WIN32
    /*  ..... code omitted ....... */
#elif defined(NETWARE)
    /*  ..... code omitted ....... */
#endif
    /* Fallback to UTC */
    php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We had to select 'UTC' because your platform doesn't provide functionality for the guessing algorithm");
    return "UTC";
}

ОК, так как это взаимодействует с date_default_timezone_set? Давайте рассмотрим эту функцию :

PHP_FUNCTION(date_default_timezone_set)
{
    char *zone;
    int   zone_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &zone, &zone_len) == FAILURE) {
        RETURN_FALSE;
    }
    if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) {
        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Timezone ID '%s' is invalid", zone);
        RETURN_FALSE;
    }
    if (DATEG(timezone)) {
        efree(DATEG(timezone));
        DATEG(timezone) = NULL;
    }
    DATEG(timezone) = estrndup(zone, zone_len);
    RETURN_TRUE;
}

Короче говоря: если вы вызываете date_default_timezone_set один раз, то guess_timezone выбирает быстрый путь чтения из переменной timezone (выполняется первое условное условие, и оно немедленно возвращается).В противном случае требуется определенное время для определения часового пояса по умолчанию, который не кэшируется (я полагаю для простоты), и если вы сделаете это в цикле, задержка начнет показываться.

2 голосов
/ 05 апреля 2011

Я полагаю, что он должен определять часовой пояс для себя каждый раз, когда он вызывается, если это не указано явно, что увеличивает время выполнения функции.

Но действительно ли это имеет значение? Сколько сценариев вы можете сделать эту дату вызова () 100 000 раз за цикл?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...