Pregunta ¿Por qué date () funciona el doble de rápido si configuramos el huso horario del código?


¿Has notado eso? date() funciona la función 2 veces más rápido de lo normal si establece la zona horaria real dentro de su secuencia de comandos antes de cualquier date() ¿llamada? Tengo mucha curiosidad sobre esto.

Mire esta simple pieza de código:

<?php

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

?>

Simplemente llama date() utilizar la función for bucle 100.000 veces. El resultado que tengo siempre está alrededor 1.6 segundos (Windows, PHP 5.3.5) pero ...

Si configuro el mismo huso horario agregando una línea absurda antes de comenzar:

date_default_timezone_set(date_default_timezone_get());

Tengo un tiempo debajo 800 ms; ~ 2 veces más rápido (el mismo servidor).

Estaba buscando una explicación razonable para este comportamiento pero no tuve éxito. Desde mi punto de vista, esta línea adicional es inútil, pero PHP no está de acuerdo conmigo.

Probé esta prueba en dos servidores de Linux (diferentes versiones de PHP) y obtuve diferentes tiempos de resultado, pero en proporción ~ 6: 1.

Nota: date.timezone propiedad en php.ini ha sido configurado correctamente (Europa / París).

Estaba buscando preguntas relacionadas aquí y no encontré nada similar. También revisé el manual para date_default_time_zone () function @ php.net y descubrí que no solo soy alguien que notó esto, ¿pero todavía no puedo entender por qué sucede eso?

¿Nadie?


32
2018-04-05 18:39


origen


Respuestas:


Actualización para PHP 5.4:

Como se documenta en la descripción de date_default_timezone_get, a partir de PHP 5.4.0 el algoritmo para adivinar la zona horaria a partir de la información del sistema ha sido eliminado del código (contraste con la fuente PHP 5.3) por lo que este comportamiento ya no existe.

Ejecutando la prueba de tiempo en mi servidor de desarrollo para verlo en acción, obtuve:

  • PHP 5.3.11: ~ 720 ms
  • PHP 5.4.3: ~ 470ms

Respuesta original:

Acabo de examinar la fuente PHP. Específicamente, todo el código relevante está en /ext/date/php_date.c.

Empecé suponiendo que si no proporciona una zona horaria para date, date_default_timezone_get es llamado para obtener uno. Aquí está esa función:

PHP_FUNCTION(date_default_timezone_get)
{
    timelib_tzinfo *default_tz;

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

OK, entonces que hace get_timezone_info ¿parece? Esta:

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;
}

Qué pasa guess_timezone? aquí es:

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";
}

OK, entonces, ¿cómo interactúa eso con date_default_timezone_set? Miremos a esa función:

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;
}

Larga historia corta: si llamas date_default_timezone_set una vez, luego guess_timezone toma el camino rápido de lectura desde el timezone variable (se cumple el primer condicional y vuelve inmediatamente). De lo contrario, lleva un tiempo calcular la zona horaria predeterminada, que no está en la memoria caché (supongo que por simplicidad), y si lo hace en un bucle, la demora comienza a mostrarse.


41
2018-04-05 18:56



Me imagino que tiene que determinar la zona horaria por sí misma cada vez que se invoca a menos que se especifique explícitamente, lo que se agrega al tiempo de ejecución de la función.

Pero realmente, ¿Importa? ¿Cuántas secuencias de comandos es probable que realice esa llamada a la fecha () 100.000 veces por ejecución?


2
2018-04-05 18:50