![](/img/trans.png)
[英]Impact of using AsParallel() and AsSequential() in the same query? C#
[英]Understanding AsParallel and AsSequential: which part of the LINQ query is concurrent?
我試圖了解我是否可以使用AsParallel
查詢留下的非線程安全類。 就像是:
src.Select(item => nonSafeClass.Process(item))
.AsParallel()
.Select(item => DoComputationalIntenseButThreadSafeWork(item));
我試圖運行以下代碼,以查看查詢鏈的哪個部分並行執行,而不是並行執行:
IEnumerable<int> array = Enumerable.Range(0, short.MaxValue).ToArray();
array.Select(i =>
{
Console.WriteLine("Step One: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).AsParallel().Select(i =>
{
Console.WriteLine("Step Two: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).AsSequential().Select(i =>
{
Console.WriteLine("Step Three: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).ToList();
但是令我驚訝的是,“第一步”和“第三步”都出現在不同的線程ID上。 我期望只為“第二步”看到不同的線程ID,因為它在AsParallel
和AsSequential
。 我的想法錯了嗎?
這是因為推遲執行 。
以及Linq中的鏈接查詢如何工作 。
如果您將其更改為最簡單的情況
array.Select(i =>
{
Console.WriteLine("Step One: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).Select(i =>
{
Console.WriteLine("Step Two: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).Select(i =>
{
Console.WriteLine("Step Three: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).ToList();
您將看到以下內容:步驟1步驟2步驟3步驟1步驟2步驟3 ... ...
現在想象一下您的假設是否正確:
首先Select()在Thread 1
(主線程)上運行。 然后,您的AsParallel
在不同的線程上運行,但是最終,最終的AsSequential()
需要在同一線程上運行,這意味着,由於Thread 1
被阻塞,使AsParallel
在不同的線程上運行沒有任何區別。
您正在考慮的流程為: 1 -> x -> 1
跟着1 -> y -> 1
等等等等。
作為一種優化,當Linq檢測到您有一個select之后是AsParallel
,它將在單獨的線程上為每次迭代運行它們。 同樣,這是因為從1 -> x -> 1 -> y
不會使任何內容以“並行”方式運行。
通過運行簡化版本來嘗試:
array.Select(i =>
{
Console.WriteLine("Step One: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).AsParallel().Select(i =>
{
Console.WriteLine("Step Two: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).ToList();
您將看到步驟1和步驟2是“序列”中的don,但是每次迭代都是在不同的線程上完成的。
但是,您的AsSequential()將在執行它的主線程上運行。
因此,我希望步驟1和步驟2 在與調用線程不同的同一線程上運行,但是步驟3在啟動鏈的同一線程上運行。
如果要實現您描述的行為,只需將查詢更改為此:
array.Select(i =>
{
Console.WriteLine("Step One: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).ToList().AsParallel().Select(i =>
{
Console.WriteLine("Step Two: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).AsSequential().Select(i =>
{
Console.WriteLine("Step Three: {0}", Thread.CurrentThread.ManagedThreadId);
return i;
}).ToList();
第一個ToList()評估將在調用線程上運行所有內容,AsParallel()然后在不同的線程上運行每個迭代(取決於ThreadPool的可用性),最后,您的AsSequential將確保順序位在調用線程上運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.