2012-03-16 13 views
7

Sono curioso di sapere come IEnumerable differisce da IObservable sotto il cofano. Capisco rispettivamente i modelli pull e push, ma come fa C#, in termini di memoria, ecc, a comunicare agli abbonati (per IObservable) che dovrebbe ricevere il successivo bit di dati in memoria da elaborare? In che modo l'istanza osservata sa che ha avuto un cambiamento nei dati da inviare agli abbonati.Come differisce IEnumerable da IObservable sotto il cofano?

La mia domanda proviene da un test che stavo eseguendo la lettura in linee da un file. Il file era di circa 6 Mb in totale.

Standard Time persi: 4.7s, linee: 36587

Rx Tempo impiegato: 0.68s, linee: 36587

Come è Rx in grado di migliorare in maniera massiccia un'iterazione normale sopra ciascuna delle righe nel file ?

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

Se si cambia l'ordine delle chiamate quando si esegue il benchmark dell'applicazione, l'RX è ancora più veloce? – user7116

+0

I tempi sono invertiti! C'è un qualche tipo di ottimizzazione in corso! Infatti, l'Rx funziona più lentamente (circa 5 secondi). – David

risposta

5

La mia impressione è che il comportamento visualizzato sta riflettendo il sistema operativo che memorizza il file nella cache. Immagino che se invertissi l'ordine delle chiamate vedresti una simile differenza di velocità, appena scambiato.

È possibile migliorare questo benchmark eseguendo alcune sessioni di riscaldamento o copiando il file di input in un file temporaneo utilizzando File.Copy prima di testare ciascuno di essi. In questo modo il file non sarebbe "caldo" e otterresti un confronto equo.

+0

corretto. si, sembra che stia accadendo qualche caching. – David

+0

Non ho alcuna differenza apprezzabile nella loro velocità per un file di 10 MB o 25 Mb, e dopo questo lo standard prende la torta (4x speedup) fino a 100 MB (il più grande che ho testato) di dati generati casualmente con virgole. Ciò ha incluso il permesso al JIT di "scaldarsi" eseguendo ogni metodo 3x prima di dare il suo risultato effettivo. Come per ogni benchmark, sarà specifico per il tuo ambiente operativo. – user7116

1

Sospetto che stiate vedendo una sorta di ottimizzazione interna del CLR. Probabilmente memorizza il contenuto del file in memoria tra le due chiamate in modo che ToObservable possa estrarre il contenuto molto più rapidamente ...

Modifica: Oh, il buon collega con il soprannome pazzo eeh ... @sixlettervariables era più veloce e probabilmente ha ragione: è piuttosto il sistema operativo che sta ottimizzando rispetto al CLR.

Problemi correlati