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不是線程安全的,因此如果您對可能從另一個線程更改的實體執行讀取/寫入操作,則應該正確同步。