7

ボンネットの下とどうIEnumerable違うのか興味があります。IObservableプル パターンとプッシュ パターンはそれぞれ理解していますが、C# は、メモリなどの観点から、処理するメモリ内の次のデータ ビットを受信する必要があることをサブスクライバー (IObservable 用) にどのように通知しますか? 監視対象のインスタンスは、サブスクライバーにプッシュするデータに変更があったことをどのように認識しますか。

私の質問は、ファイルから行を読み取って実行していたテストから来ています。ファイルは合計で約 6Mb でした。

標準所要時間: 4.7 秒、ライン数: 36587

Rx 所要時間: 0.68 秒、回線数: 36587

Rx はどのようにしてファイル内の各行の通常の繰り返しを大幅に改善できるのでしょうか?

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();
    }
}
4

2 に答える 2

5

私の推測では、あなたが見ている動作は、ファイルをキャッシュしている OS を反映しているということです。呼び出しの順序を逆にすると、交換しただけで同様の速度の違いが見られると思います。

このベンチマークは、ウォームアップを数回実行するか、File.Copy各テストの前に を使用して入力ファイルを一時ファイルにコピーすることで改善できます。この方法では、ファイルは「ホット」ではなく、公正な比較ができます。

于 2012-03-16T17:27:07.213 に答える
1

CLR の何らかの内部最適化が見られるのではないかと思います。おそらく、2回の呼び出しの間にファイルのコンテンツをメモリにキャッシュするためToObservable、コンテンツをはるかに高速にプルできます...

編集: ああ、クレイジーなニックネームを持つ良い同僚 eeh ... @sixlettervariables はより高速であり、彼はおそらく正しいです。CLR よりも最適化しているのは OS です。

于 2012-03-16T17:31:42.707 に答える