Linq отложенное исполнение
Я написал простую программу, вот как она выглядит, некоторые детали скрыты:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace routeaccounts
{
class Program
{
static void Main(string[] args)
{
//Draw lines from source file
var lines = File.ReadAllLines("accounts.txt").Select(p => p.Split('\t'));
//Convert lines into accounts
var accounts = lines.Select(p => new Account(p[0], p[1], p[2], p[3]));
//Submit accounts to router
var results = accounts.Select(p => RouteAccount(p));
//Write results list to target file
WriteResults("results.txt", results);
}
private static void WriteResults(string filename, IEnumerable<Result> results)
{
... disk write call ...
}
private static Result RouteAccount(Account account)
{
... service call ...
}
}
}
У меня такой вопрос - очевидно, что при выборе из контекста данных выполнение откладывается. Если вы заметили, что в первом операторе функции 'Main' я запрашиваю у File.ReadAllLines("accounts.txt"). Это плохой выбор? Если я перечислю окончательный результат, будет ли это утверждение повторяться?
Я могу просто.ToArray() или забрать результаты заранее, если я знаю, что это проблема, но мне интересно знать, что происходит за кулисами.
3 ответа
Он не будет читать файл повторно, нет - потому что эта часть выполнения не откладывается. Он вернет массив, а затем вызов Select
вернет вам последовательность... проекция будет отложена, но чтение файла не будет. Этот массив будет оставаться в памяти до тех пор, пока все ссылки на него (прямо или косвенно) не будут пригодны для сбора мусора... ему не нужно будет перечитывать файл.
С другой стороны, вы можете прочитать результаты, используя ToList()
или что-то подобное в любом случае - потому что таким образом вы можете обнаружить любые ошибки, прежде чем начать писать результаты. Довольно часто хорошая идея, чтобы убедиться, что у вас есть все необходимые данные, прежде чем вы начнете выполнять код с побочными эффектами (что я представляю WriteResults
делает). Очевидно, что он менее эффективен с точки зрения количества данных, необходимых в памяти за один раз, хотя... это баланс, который вам придется взвесить самостоятельно.
Лучше использовать File.ReadLines
в.NET 4.0, чтобы получить ленивое чтение файла тоже. Как сейчас, чтение файла не откладывается и будет считывать весь файл в память, когда File.ReadAllLines
возвращается. Это случится только один раз.
//File is read now, but split later.
var lines = File.ReadAllLines("accounts.txt").Select(p => p.Split('\t'));
//Accounts are new'd up later.
var accounts = lines.Select(p => new Account(p[0], p[1], p[2], p[3]));
//Accounts are Routed later.
var results = accounts.Select(p => RouteAccount(p));
//Write results list to target file
WriteResults("results.txt", results);
private static void WriteResults(string filename, IEnumerable<Result> results)
{
//file is split, accounts are new'd up and routed by enumerating results
List<Result> items = results.ToList();
}