在多线程应用程序中共享IEnumerable <t>和IQueryable <t> </t> </t>

时间:2011-04-15 12:07:20

标签: c# multithreading ienumerable iqueryable

我很少怀疑在多线程应用程序中如何访问共享IEnumerableIQueryable

请考虑此代码段。

ObservableCollection<SessionFile> files = /* some code */
IEnumerable<Pattern> allFilePatterns= /*some query */

foreach (Pattern pattern in allFilePatterns)
{
   string iclFilePath = Path.Combine(pattern.Location, pattern.Filename);
   SessionFile sfile = new SessionFile(iclFilePath, pattern.AnalysisDate);

   SomeDelegate invoker = new SomeDelegate(sfile.SomeHandler);
   invoker.BeginInvoke(allFilePatterns, null, null);

   files.Add(sfile );
}

如您所见,我正在使用BeginInvoke()相同的实例allFilePatterns传递给名为sfile.SomeHandler的每个处理程序。

假设在SomeHandler中,我在foreach循环中迭代 allFilePatterns ,如下所示:

void SomeHandler(IEnumerable<Pattern> allFilePatterns)
{
    foreach(Pattern pattern in allFilePatterns)
    {
          //some code
    }
}

现在我的疑问是:因为BeginInvoke()是异步的,这意味着所有文件的所有foreach中的所有SomeHandler将并行执行(每个文件都在自己的线程中), IEnumerable的共享实例按预期/正常枚举?这是一种正确的方法吗?我可以在多个线程中共享相同IEnumerable实例,并且并行枚举它吗?

如果我在上面的代码中使用IQueryable而不是IEnumerable怎么办?我应该注意哪些副作用?

如果它不是线程安全的,那么我应该使用什么?

请注意我使用IQueryable进行数据库查询,因为我不想从数据库中提取所有数据。因此,我想尽可能避免IQueryable.ToList()

4 个答案:

答案 0 :(得分:5)

这取决于实施。 IEnumerable<T>的某些实现也会实现IEnumerator<T>,并从GetEnumerator()返回。在这种情况下,它显然不是线程安全的......

至于IQueryable<T>,它还取决于实施。例如,Entity Framework上下文不是线程安全的,只能在创建它们的线程上正常工作。

所以这个问题没有独特的答案......它可能适用于某些实现,而不适用于其他实现。

答案 1 :(得分:1)

当你作为参数传递给委托时,我会ToList()你的枚举实际创建一个新的集合供线程使用并避免问题。

但是,我想知道为什么你需要枚举枚举枚举的每个元素N次(有效N ^ 2)?这听起来效率低下。

编辑:更新了我的意图

答案 2 :(得分:0)

答案 3 :(得分:0)

嗯,如果使用非线程安全的IQueryable(如实体框架查询),可以做的一件事就是在一个线程中枚举结果,然后传递结果必要的新线程。

然后,如果IQueryable / IEnumerable是线程安全的并不重要。