我正在查看VS2010 Concurrency Profiler的输出,我注意到我在某些LINQ运算符周围遇到了一些线程争用。以下是引起争用的声明:
m_dictionary.PermutableSubunits.Select(subunit => subunit.Number).ToArray()
LINQ运算符是否阻止?我是否应该更谨慎地在作为Parallel.ForEach的一部分运行的任务中使用它们?
答案 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不是线程安全的,因此如果您正在对可能从另一个线程更改的实体执行读/写操作,那么您应该正确同步。