【问题标题】:Parallel.ForEach and Cannot read from closed TextReader exceptionParallel.ForEach 和无法从已关闭的 TextReader 异常中读取
【发布时间】:2011-10-31 08:41:49
【问题描述】:

我有一个包含各种提要 URL 的文本文件。我正在使用以下代码读取集合(IEnumerable)中的所有 URL:

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 的数量,即调用 URL 对象上的 Count() 方法的代码,我就会遇到以下异常。例外:

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 循环运行良好。

有人知道这里出了什么问题吗?

【问题讨论】:

  • some business logic 发生了什么?

标签: c# task-parallel-library parallel.foreach


【解决方案1】:

不要在不需要时使用var(或者当类型明显多余时)。在这种情况下,它会隐藏正在发生的事情,并且您会对结果感到惊讶。

File.ReadLines 方法不会读取所有行并返回一个集合,它会返回一个枚举器,当您从中获取项目时读取行。它返回的类型不是字符串数组,而是IEnumerable&lt;string&gt;,如果你已经指定了变量的类型,你会注意到:

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

这会导致编译器错误,因为该方法不返回数组,所以您会看到结果不是您所期望的。

当您在枚举器上使用Count() 方法时,它会读取文件中的所有行以进行计数,因此当您稍后尝试再次使用枚举时,它已经读取了所有行并关闭TextReader

使用File.ReadAllLines 方法读取文件中的所有行,而不是获取枚举数:

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

现在您可以多次使用该数组。

【讨论】:

  • 谢谢。吸取教训,仅在必要时使用“var”关键字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-29
  • 2013-06-10
  • 2011-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多