0

我正在查看VS2010并发事件探查器的输出,我注意到我在一些LINQ运算符周围发生了一些线程争用。以下是导致争用的声明:LINQ操作符是否阻塞?

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

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

+0

你是指LINQ操作符,我希望它是单线程的还是使用线程池的PLINQ操作符?我不确定我了解你的问题。 – 2011-04-17 02:11:08

+0

我的意思是LINQ运算符(如上面的Select()和ToArray()),而不是PLINQ(注意上面没有.AsParallel())。上面的代码在由Parallel.ForEach方法启动的任务中运行。这是你想知道的吗? – 2011-04-17 20:30:54

回答

2

我假定你问的是LINQ to Objects,所以你的代码中的Select调用对应Enumerable.Select(..)。

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

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

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

+0

感谢伊戈尔,你是对的我正在使用Linq到对象,我也使用服务器GC。在重写某些从Linq到很老的for循环的代码段时,我注意到了性能的提高,所以我想我会暂时继续这样做。 – 2011-04-27 13:57:46

0

它不应该被阻塞,但是如果你使用Linq-to-SQL,如果你的查询需要很长时间来执行,那么可能需要很长的时间......总之,任何时候你在做什么多线程你应该“更加小心”,或者像他们说的那样:“仔细地讲话!”

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