yyyy ssz specific now ddthh c# optimization datetime formatting

ssz - set datetime now format c#



¿Cómo puedo mejorar el rendimiento del código utilizando DateTime.ToString? (4)

En mi aplicación de decodificación de binario a texto (.NET 2.0) encontré que la línea:

logEntryTime.ToString("dd.MM.yy HH:mm:ss:fff")

lleva el 33% del tiempo total de procesamiento. ¿Alguien tiene alguna idea sobre cómo hacerlo más rápido?

EDITAR: esta aplicación se utiliza para procesar algunos registros binarios y actualmente lleva 15 horas en ejecutarse. Así que 1/3 de esto será de 5 horas.

EDITAR: Estoy usando NProf para perfilar. La aplicación está procesando alrededor de 17 GBytes de registros binarios.


¿Estás seguro de que lleva el 33% del tiempo? ¿Cómo has medido eso? Me suena más que un poco sospechoso ...

Esto hace las cosas un poco más rápidas:

Basic: 2342ms Custom: 1319ms

O si cortamos el IO ( Stream.Null ):

Basic: 2275ms Custom: 839ms

using System.Diagnostics; using System; using System.IO; static class Program { static void Main() { DateTime when = DateTime.Now; const int LOOP = 1000000; Stopwatch basic = Stopwatch.StartNew(); using (TextWriter tw = new StreamWriter("basic.txt")) { for (int i = 0; i < LOOP; i++) { tw.Write(when.ToString("dd.MM.yy HH:mm:ss:fff")); } } basic.Stop(); Console.WriteLine("Basic: " + basic.ElapsedMilliseconds + "ms"); char[] buffer = new char[100]; Stopwatch custom = Stopwatch.StartNew(); using (TextWriter tw = new StreamWriter("custom.txt")) { for (int i = 0; i < LOOP; i++) { WriteDateTime(tw, when, buffer); } } custom.Stop(); Console.WriteLine("Custom: " + custom.ElapsedMilliseconds + "ms"); } static void WriteDateTime(TextWriter output, DateTime when, char[] buffer) { buffer[2] = buffer[5] = ''.''; buffer[8] = '' ''; buffer[11] = buffer[14] = buffer[17] = '':''; Write2(buffer, when.Day, 0); Write2(buffer, when.Month, 3); Write2(buffer, when.Year % 100, 6); Write2(buffer, when.Hour, 9); Write2(buffer, when.Minute, 12); Write2(buffer, when.Second, 15); Write3(buffer, when.Millisecond, 18); output.Write(buffer, 0, 21); } static void Write2(char[] buffer, int value, int offset) { buffer[offset++] = (char)(''0'' + (value / 10)); buffer[offset] = (char)(''0'' + (value % 10)); } static void Write3(char[] buffer, int value, int offset) { buffer[offset++] = (char)(''0'' + (value / 100)); buffer[offset++] = (char)(''0'' + ((value / 10) % 10)); buffer[offset] = (char)(''0'' + (value % 10)); } }


¿Sabes qué tan grande será cada registro en los registros binarios y de texto? Si es así, puede dividir el procesamiento del archivo de registro en una serie de subprocesos que darían un mejor uso a una PC con varios núcleos / procesador. Si no le importa que el resultado se encuentre en archivos separados, sería una buena idea tener un disco duro por núcleo de esa manera, así reduciría la cantidad de movimiento de los cabezales.


Es lamentable que .NET no tenga un tipo de "formateador" que pueda analizar un patrón y recordarlo.

Si siempre está utilizando el mismo formato, es posible que desee elaborar un formateador a mano para hacer exactamente eso. Algo a lo largo de las líneas de:

public static string FormatDateTime(DateTime dt) { char[] chars = new char[21]; Write2Chars(chars, 0, dt.Day); chars[2] = ''.''; Write2Chars(chars, 3, dt.Month); chars[5] = ''.''; Write2Chars(chars, 6, dt.Year % 100); chars[8] = '' ''; Write2Chars(chars, 9, dt.Hour); chars[11] = '' ''; Write2Chars(chars, 12, dt.Minute); chars[14] = '' ''; Write2Chars(chars, 15, dt.Second); chars[17] = '' ''; Write2Chars(chars, 18, dt.Millisecond / 10); chars[20] = Digit(dt.Millisecond % 10); return new string(chars); } private static void Write2Chars(char[] chars, int offset, int value) { chars[offset] = Digit(value / 10); chars[offset+1] = Digit(value % 10); } private static char Digit(int value) { return (char) (value + ''0''); }

Esto es bastante feo, pero probablemente sea mucho más eficiente ... ¡haz un punto de referencia, por supuesto!


Esta no es una respuesta en sí misma, sino más bien un agregado a la excelente respuesta de Jon Skeet , que ofrece una variante para el formato "s" (ISO):

/// <summary> /// Implements a fast method to write a DateTime value to string, in the ISO "s" format. /// </summary> /// <param name="dateTime">The date time.</param> /// <returns></returns> /// <devdoc> /// This implementation exists just for performance reasons, it is semantically identical to /// <code> /// text = value.HasValue ? value.Value.ToString("s") : string.Empty; /// </code> /// However, it runs about 3 times as fast. (Measured using the VS2015 performace profiler) /// </devdoc> public static string ToIsoStringFast(DateTime? dateTime) { if (!dateTime.HasValue) { return string.Empty; } DateTime dt = dateTime.Value; char[] chars = new char[19]; Write4Chars(chars, 0, dt.Year); chars[4] = ''-''; Write2Chars(chars, 5, dt.Month); chars[7] = ''-''; Write2Chars(chars, 8, dt.Day); chars[10] = ''T''; Write2Chars(chars, 11, dt.Hour); chars[13] = '':''; Write2Chars(chars, 14, dt.Minute); chars[16] = '':''; Write2Chars(chars, 17, dt.Second); return new string(chars); }

Con el serializador de 4 dígitos como:

private static void Write4Chars(char[] chars, int offset, int value) { chars[offset] = Digit(value / 1000); chars[offset + 1] = Digit(value / 100 % 10); chars[offset + 2] = Digit(value / 10 % 10); chars[offset + 3] = Digit(value % 10); }

Esto se ejecuta aproximadamente 3 veces más rápido. (Medido utilizando el perfilador de rendimiento VS2015)