Чем 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.