Почему gmmktime() быстрее, чем mktime(), когда в руководстве по php сказано, что первый использует последний внутри?

#php #performance #micro-optimization

#php #Производительность #микрооптимизация

Вопрос:

Согласно описанию gmmktime() в руководстве по PHP, он использует mktime() внутри. Тем не менее, когда я запускаю следующий код, выполнение цикла mktime занимает чуть менее 9 секунд, в то время как просмотр gmmktime занимает чуть менее 2 секунд. Как это может быть?

 <?php
$count = 1000000;

$startTime = microtime(true);
for ($i = 0; $i < $count; $i  )
{
  mktime();
}
$endTime = microtime(true);
printf("mktime: %.4f secondsn", $endTime - $startTime);


$startTime = microtime(true);
for ($i = 0; $i < $count; $i  )
{
  gmmktime();
}
$endTime = microtime(true);
printf("gmmktime: %.4f secondsn", $endTime - $startTime);
  

Вывод:

 mktime: 8.6714 seconds
gmmktime: 1.6906 seconds
  

Ответ №1:

Скорее всего, документация лжет вам о том, как gmmktime() это реализовано, или это означает, что используется функция C. mktime()

Если мы посмотрим на фактический код, оба gmmktime() и mktime() перейдем к внутренней php_mktime функции, которая принимает gmt параметр (установленный 1 для gmmktime() ). Если gmt равно нулю, то он должен выполнить некоторую дополнительную работу ( // -комментарии, которые я добавил, другие из исходного кода):

 /* Initialize structure with current time */
now = timelib_time_ctor();
if (gmt) {
    timelib_unixtime2gmt(now, (timelib_sll) time(NULL));
} else {
    tzi = get_timezone_info(TSRMLS_C);
    now->tz_info = tzi;
    now->zone_type = TIMELIB_ZONETYPE_ID;
    timelib_unixtime2local(now, (timelib_sll) time(NULL));
}

// ... snip shared code

/* Update the timestamp */
if (gmt) {
    // NOTE: Setting the tzi parameter to NULL skips a lot of work in timelib_update_ts
    // (and do_adjust_timezone)
    timelib_update_ts(now, NULL);
} else {
    timelib_update_ts(now, tzi);
}

/* Support for the deprecated is_dst parameter */
if (dst != -1) {
    php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "The is_dst parameter is deprecated");
    if (gmt) {
        /* GMT never uses DST */
        if (dst == 1) {
            adjust_seconds = -3600;
        }
    } else {
        /* Figure out is_dst for current TS */
        timelib_time_offset *tmp_offset;
        tmp_offset = timelib_get_time_zone_info(now->sse, tzi);
        if (dst == 1 amp;amp; tmp_offset->is_dst == 0) {
            adjust_seconds = -3600;
        }
        if (dst == 0 amp;amp; tmp_offset->is_dst == 1) {
            adjust_seconds =  3600;
        }
        timelib_time_offset_dtor(tmp_offset);
    }
}
  

Я подозреваю, что вы можете обнаружить, что каждый раз, когда вы это делаете mktime() , он повторно открывает файл описания часового пояса, чтобы прочитать его и получить правильные смещения часового пояса / летнего времени. При использовании gmmktime() он пропускает это, используя внутренний нулевой часовой пояс для GMT — таким образом, намного быстрее.