Чем IEnumerable отличается от IObservable под капотом?

Мне интересно, как IEnumerable отличается от IObservable под капотом. Я понимаю шаблоны "тянуть" и "толкать" соответственно, но как C# с точки зрения памяти и т. Д. Уведомляет подписчиков (для IObservable), что он должен получить следующий бит данных в памяти для обработки? Как наблюдаемый экземпляр узнал, что произошли изменения в данных, которые нужно передать подписчикам?

Мой вопрос возник из теста, который я выполнял в виде строк из файла. Файл был около 6 МБ в общей сложности.

Стандартное время: 4,7 с, количество строк: 36587.

Rx Time Taken: 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();
    }
}

2 ответа

Я догадываюсь, что поведение, которое вы видите, отражает кеширование файла операционной системой. Я полагаю, если бы вы изменили порядок вызовов, вы бы увидели похожую разницу в скоростях, просто поменялись местами.

Вы можете улучшить этот тест, выполнив несколько прогонов прогона или скопировав входной файл во временный файл, используя File.Copy до тестирования каждого. Таким образом, файл не будет "горячим", и вы получите справедливое сравнение.

Я подозреваю, что вы видите какую-то внутреннюю оптимизацию CLR. Вероятно, он кэширует содержимое файла в памяти между двумя вызовами, так что ToObservable может тянуть контент намного быстрее...

Редактировать: О, хороший коллега с сумасшедшим псевдонимом eeh... @sixlettervariables был быстрее, и он, вероятно, прав: скорее оптимизирует ОС, чем CLR.

Другие вопросы по тегам