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();
    }   
Другие вопросы по тегам