LINQ运算符会阻塞吗?

时间:2011-04-16 19:19:32

标签: linq concurrency task-parallel-library parallel-extensions

我正在查看VS2010 Concurrency Profiler的输出,我注意到我在某些LINQ运算符周围遇到了一些线程争用。以下是引起争用的声明:

m_dictionary.PermutableSubunits.Select(subunit => subunit.Number).ToArray()

LINQ运算符是否阻止?我是否应该更谨慎地在作为Parallel.ForEach的一部分运行的任务中使用它们?

2 个答案:

答案 0 :(得分:2)

我假设您询问LINQ to Objects,因此代码中的Select调用对应于Enumerable.Select(..)。

LINQ to Objects运算符本身不会显式阻止正在执行的线程。但是,它们会分配内存:例如,ToArray运算符将分配更大和更大的数组,以便缓冲结果。

并且,内存分配可以导致线程阻塞。当您分配内存时,CLR或操作系统可能需要获取一些锁定才能找到一块空闲内存。更重要的是,CLR可能会在您分配内存时决定运行垃圾收集(GC),这可能会导致严重的线程阻塞。

如果服务器GC非常适合您的应用程序,您可以尝试打开它并查看吞吐量是否有所改善。此外,您通常可以编写非LINQ代码,执行比LINQ to Objects查询更少的内存分配。在您的特定示例中,我相信LINQ to Objects将开始将结果生成为一个小数组,在结果不适合的任何时候分配更大的数组。您的自定义实现可能能够在开始时分配正确大小的数组,从而避免一堆不必要的分配。

答案 1 :(得分:0)

它不应该阻止,但是如果你使用Linq-to-SQL,如果你的查询花了很长时间执行它可能会花费很长时间...一般来说,任何时候你都在做多线程的事情你应该“更加小心”或正如他们所说:“小心翼翼!”

但是,如果您遇到争用问题,那么您应该真正分析您实际在做什么。 Linq不是线程安全的,因此如果您正在对可能从另一个线程更改的实体执行读/写操作,那么您应该正确同步。