Optimización de alternativas a DateTime.Now
Un colega y yo estamos discutiendo este tema y espero obtener algunas opiniones externas sobre si la solución que propongo es o no una buena idea.
Primero, un descargo de responsabilidad: me doy cuenta de que la noción de "optimizar DateTime.Now
" les parece una locura a algunos de ustedes. Tengo un par de defensas preventivas:
- A veces sospecho que aquellas personas que siempre dicen: "Las computadoras son rápidas; la legibilidad siempre viene antes que la optimización" a menudo hablan desde su experiencia en el desarrollo de aplicaciones donde el rendimiento, aunque puede ser importante , no lo es . Me refiero a la necesidad de que las cosas sucedan lo más instantáneamente posible, es decir, en nanosegundos (en ciertas industrias, esto sí importa, por ejemplo, el comercio de alta frecuencia en tiempo real).
- Incluso teniendo esto en cuenta, el enfoque alternativo que describo a continuación es, de hecho, bastante legible. No es un truco extraño, sólo un método simple que funciona de manera confiable y rápida.
- Hemos realizado pruebas.
DateTime.Now
es lento (relativamente hablando). El método siguiente es más rápido.
Ahora, pasemos a la pregunta en sí.
Básicamente, a partir de las pruebas, descubrimos que DateTime.Now
se necesitan aproximadamente 25 tics (alrededor de 2,5 microsegundos) para ejecutarse. Por supuesto, esto se promedia entre miles y millones de llamadas. Parece que la primera llamada en realidad lleva una cantidad significativa de tiempo y las llamadas posteriores son mucho más rápidas. Pero aun así, 25 ticks es el promedio.
Sin embargo, mi colega y yo notamos que DateTime.UtcNow
lleva mucho menos tiempo ejecutarlo: en promedio, apenas 0,03 microsegundos.
Dado que nuestra aplicación nunca se ejecutará mientras haya un cambio en el horario de verano , mi sugerencia fue crear la siguiente clase:
public static class FastDateTime {
public static TimeSpan LocalUtcOffset { get; private set; }
public static DateTime Now {
get { return DateTime.UtcNow + LocalUtcOffset; }
}
static FastDateTime() {
LocalUtcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
}
}
En otras palabras, determine el desplazamiento UTC para la zona horaria local una vez (al inicio) y desde ese momento en adelante aproveche la velocidad de DateTime.UtcNow
para obtener la hora actual mucho más rápido a través de FastDateTime.Now
.
Podría ver que esto sería un problema si el desplazamiento UTC cambiara durante el tiempo que se estaba ejecutando la aplicación (si, por ejemplo, la aplicación se estaba ejecutando durante la noche); pero como ya dije, en nuestro caso eso no sucederá.
Mi colega tiene una idea diferente sobre cómo hacerlo, lo cual es demasiado complicado para que yo lo explique aquí. En última instancia, hasta donde puedo decir , ambos enfoques arrojan un resultado preciso, siendo el mío un poco más rápido (~0,07 microsegundos frente a ~0,21 microsegundos).
Lo que quiero saber es:
- ¿Me estoy perdiendo de algo? Dado el hecho mencionado anteriormente de que la aplicación sólo se ejecutará dentro del plazo de una sola fecha, ¿es
FastDateTime.Now
segura? - ¿ Alguien más puede pensar en una forma aún más rápida de obtener la hora actual?
¿Podría simplemente usar DateTime.UtcNow y convertir solo a la hora local cuando se presenten los datos? Ya ha determinado que DateTime.UtcNow es mucho más rápido y eliminará cualquier ambigüedad en torno al horario de verano.
Una diferencia entre el resultado de
DateTime.Now
y
DateTime.UtcNow + LocalUtcOffset
es el valor de la propiedad Kind: Local vs Utc respectivamente. Si el DateTime resultante se pasa a una biblioteca de terceros, considere devolverlo
DateTime.SpecifyKind(DateTime.UtcNow + LocalUtcOffset, DateTimeKind.Local)
Me gusta tu solución. Hice algunas pruebas para ver cuánto más rápido es en comparación con el normal.DateTime.Now
DateTime.UtcNow
es 117 veces más rápido queDateTime.Now
Usar DateTime.UtcNow
es suficientemente bueno si sólo nos interesa la duración y no el tiempo en sí. Si todo lo que necesitamos es calcular la duración de una sección de código específica (hacer duration= End_time - Start_time
), entonces la zona horaria no es importante y DateTime.UtcNow
es suficiente.
Pero si necesitamos el tiempo mismo, entonces debemos hacerlo.
DateTime.UtcNow + LocalUtcOffset
Simplemente agregando el lapso de tiempo se ralentiza un poco y ahora, según mis pruebas, somos solo 49 veces más rápidos que el normal.DateTime.Now
Si ponemos este cálculo en una función/clase separada como se sugiere, llamar al método nos ralentiza aún más y solo somos 34 veces más rápidos.
¡¡¡Pero incluso 34 veces más rápido es mucho !!!
En resumen, Usar DateTime.UtcNow
es mucho más rápido queDateTime.Now
La única forma que encontré para mejorar la clase sugerida es usar código en línea: DateTime.UtcNow + LocalUtcOffset
en lugar de llamar al método de la clase
Por cierto, intentar forzar al compilador a compilar en línea mediante el uso [MethodImpl(MethodImplOptions.AggressiveInlining)]
no pareció acelerar las cosas.
Para responder en orden inverso:
2) No puedo pensar en una manera más rápida.
1) Valdría la pena comprobar si hay alguna mejora en el marco de trabajo como la que acaban de anunciar para System.IO.
Es difícil estar seguro de la seguridad, pero es algo que pide a gritos muchas pruebas unitarias. Me viene a la mente el horario de verano. El System One obviamente está muy curtido en batalla, mientras que el tuyo no.