2012-03-16 22 views
7

Tengo curiosidad sobre cómo IEnumerable difiere de IObservable debajo del capó. Entiendo los patrones de extracción y empuje respectivamente, pero ¿cómo notifica C#, en términos de memoria, etc. a los suscriptores (para IObservable) que debe recibir el siguiente bit de datos en la memoria para procesar? ¿Cómo sabe la instancia observada que ha tenido un cambio en los datos para enviar a los suscriptores?¿Cómo se diferencia IEnumerable de IObservable debajo del capó?

Mi pregunta proviene de una prueba que estaba realizando leyendo en líneas de un archivo. El archivo tenía aproximadamente 6 Mb en total.

Tiempo estándar tomados: 4.7s, líneas: 36587

Rx tiempo empleado: 0.68s, líneas: 36587

Cómo es Rx capaz de mejorar de forma masiva una iteración de lo normal en cada una de las líneas en el archivo ?

private static void ReadStandardFile() 
{ 
    var timer = Stopwatch.StartNew(); 
    var linesProcessed = 0; 

    foreach (var l in ReadLines(new FileStream(_filePath, FileMode.Open))) 
    { 
     var s = l.Split(','); 
     linesProcessed++; 
    } 

    timer.Stop(); 

    _log.DebugFormat("Standard Time Taken: {0}s, lines: {1}", 
     timer.Elapsed.ToString(), linesProcessed); 
} 

private static void ReadRxFile() 
{ 
    var timer = Stopwatch.StartNew(); 
    var linesProcessed = 0; 

    var query = ReadLines(new FileStream(_filePath, FileMode.Open)).ToObservable(); 

    using (query.Subscribe((line) => 
    { 
     var s = line.Split(','); 
     linesProcessed++; 
    })); 

    timer.Stop(); 

    _log.DebugFormat("Rx Time Taken: {0}s, lines: {1}", 
     timer.Elapsed.ToString(), linesProcessed); 
} 

private static IEnumerable<string> ReadLines(Stream stream) 
{ 
    using (StreamReader reader = new StreamReader(stream)) 
    { 
     while (!reader.EndOfStream) 
      yield return reader.ReadLine(); 
    } 
} 
+0

Si cambia el orden de sus llamadas cuando compara esta aplicación, ¿la RX es aún más rápida? – user7116

+0

¡Los tiempos se invierten! ¡Hay algún tipo de optimización! De hecho, el Rx uno corre más despacio (alrededor de 5 segundos). – David

Respuesta

5

Mi corazonada es el comportamiento que está viendo está reflejando el sistema operativo caché del archivo. Me imagino que si invirtieras el orden de las llamadas, verías una diferencia similar en las velocidades, solo cambiadas.

Puede mejorar este punto de referencia realizando algunas ejecuciones de calentamiento o copiando el archivo de entrada en un archivo temporal usando File.Copy antes de probar cada una. De esta forma, el archivo no estaría "caliente" y obtendría una comparación justa.

+0

Correcto. sí, parece que algo de almacenamiento en caché está sucediendo. – David

+0

No obtengo una diferencia apreciable en su velocidad para un archivo de 10MB o 25Mb, y después de eso el estándar se lleva la palma (4x aceleración) hasta 100MB (el más grande que probé) de datos generados aleatoriamente con comas. Esto incluía permitir que el JIT "calentara" ejecutando cada método 3 veces antes dado su resultado real. Al igual que con cualquier punto de referencia, será específico para su entorno operativo. – user7116

1

Sospecho que está viendo algún tipo de optimización interna del CLR. Probablemente almacena en caché el contenido del archivo en la memoria entre las dos llamadas para que ToObservable pueda extraer el contenido mucho más rápido ...

Editar: Oh, el buen colega con el sobrenombre loco eeh ... @sixlettervariables fue más rápido y probablemente tenga razón: es más bien el SO el que optimiza que el CLR.

Cuestiones relacionadas