Parallel.ForEach и Cannot read из закрытого исключения TextReader - PullRequest
1 голос
/ 31 октября 2011

У меня есть текстовый файл, содержащий URL различных каналов. Я читаю все URL в коллекции (IEnumerable), используя следующий код:

var URLs = File.ReadLines(Path.GetFullPath(@"Resources\FeedList.txt"));

В следующей строке я печатаю общее количество:

Console.WriteLine("Total Number of feeds : {0}",URLs.Count());

И после этого я использую конструкцию Parellel.ForEach для выполнения некоторой логики, соответствующей каждому URL. Ниже приведен код, который я использую:

Parallel.ForEach(URLs, (url) =>
                                       {
                                           // Some business logic
                                       });

Проблема в том, что я получаю следующее исключение, как только добавляю код для печати номера URL-адреса, то есть кода, который вызывает метод Count () для объекта URL-адресов. Исключение:

Total Number of feeds : 78

Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.ObjectDisposedException: Cannot read from a closed TextReader.
   at System.IO.__Error.ReaderClosed()
   at System.IO.StreamReader.ReadLine()
   at System.IO.File.<InternalReadLines>d__0.MoveNext()
   at System.Collections.Concurrent.Partitioner.DynamicPartitionerForIEnumerable`1.InternalPartitionEnumerator.GrabNextChunk(Int32 requestedChunkSize)
   at System.Collections.Concurrent.Partitioner.DynamicPartitionEnumerator_Abstract`2.MoveNext()
   at System.Threading.Tasks.Parallel.<>c__DisplayClass32`2.<PartitionerForEachWorker>b__30()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass7.<ExecuteSelfReplicating>b__6(Object )
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
   at System.Threading.Tasks.Parallel.PartitionerForEachWorker[TSource,TLocal](Partitioner`1 source, ParallelOptions parallelOptions, Action`1 simpleBody, Action`2 bodyWi
   at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IEnumerable`1 source, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Action`3
   at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable`1 source, Action`1 body)
   at DiscoveringGroups.Program.Main(String[] args) in C:\Users\Pawan Mishra\Documents\Visual Studio 2010\Projects\ProgrammingCollectiveIntelligence\DiscoveringGroups\Pro
Press any key to continue . . .

И если я удаляю / закомментирую строку, которая печатает значение счетчика, цикл Parallel.ForEach работает нормально.

Кто-нибудь имеет представление о том, что здесь происходит не так?

1 Ответ

4 голосов
/ 31 октября 2011

Не используйте var, когда вам это не нужно (или когда тип явно избыточен).В этом случае он скрывает то, что происходит, и вы удивляетесь результату.

Метод File.ReadLines не читает все строки и не возвращает коллекцию, он возвращает перечислитель, который читает строки, когда вы получаетепредметы из него.Тип, который он возвращает, является не строковым массивом, а IEnumerable<string>, что вы заметили бы, если бы указали тип для переменной:

string[] URLs = File.ReadLines(Path.GetFullPath(@"Resources\FeedList.txt"));

Это приводит к ошибке компилятора, поскольку метод нене возвращать массив, поэтому вы бы увидели, что результат не соответствует ожидаемому.

Когда вы используете метод Count() в перечислителе, он будет читать все строки в файле, чтобыпосчитайте их, поэтому, когда вы позже попытаетесь использовать перечисление снова, оно уже прочитало все строки и закрыло TextReader.

Используйте метод File.ReadAllLines, чтобы прочитать все строки в файле вместополучение перечислителя:

string[] URLs = File.ReadAllLines(Path.GetFullPath(@"Resources\FeedList.txt"));

Теперь вы можете использовать массив несколько раз.

...