首先當Break被調用後,迴圈中當前調用Break的執行後的迭代就沒有必要去執行了,由於並存執行打亂了執行順序,所以這個時候很可能某些不需要執行的迭代已經執行完了,這個沒辦法(也沒必要)去取消它,當然調用Break後沒有必要執行且沒有開始執行的迭代最終不會被執行。
上面只討論了“已經執行完”和“沒有執行的狀況”,對於正在執行的卻沒有必要執行的迭代,同樣沒辦法將他停止,此時ParallelLoopState.LowestBreakIteration(類型是long?,預設是null)則會成為最小的調用Break的迭代索引。
來看第一個例子,我們從1-20命令他迭代20次,但是如果等於1的話,調用Break,由於是1,所以Break會很快調用。同樣由於每次迭代沒有具體執行代碼,所以不會存在“不需要執行的迭代正在運行這種情況”。
代碼:
//統計執行次數
int count = 0;
Parallel.For(1, 21, (i, state) =>
{
//輸出:迭代個數,線程ID和LowestBreakIteration
Console.WriteLine("迭代 {0} 線程 {1} LowestBreakIteration {2}",
i,
Thread.CurrentThread.ManagedThreadId,
state.LowestBreakIteration);
if (i == 1)
state.Break();
Interlocked.Increment(ref count);
});
Console.WriteLine("執行次數:{0}", count);
我的電腦的輸出:
迭代 1 線程 1 LowestBreakIteration
迭代 6 線程 3 LowestBreakIteration
迭代 11 線程 4 LowestBreakIteration
迭代 16 線程 5 LowestBreakIteration
迭代 2 線程 6 LowestBreakIteration
執行次數:5
可以看到,有5個獨立線程分別進行了1, 6, 11, 16, 2的迭代的執行,其中只有1是必須執行的,而其他迭代的執行是由於此時並存執行還不知道Break的調用。等Break中斷髮生後,剩下的沒有必要執行的迭代全部沒有執行,一共只執行了5次!
最後由於迭代執行時間很短,不存在“正在執行的不需要的迭代”,所以LowestBreakIteration總是null。
第二個例子,和上一個一樣,只不過在迭代執行加入了Thread.Sleep來類比耗費時間的工作。這樣的話就存在了“正在執行的不需要的迭代”,也就是說當一個執行線程正在工作時才發現原來自己沒必要運行!
代碼:
//統計執行次數
int count = 0;
Parallel.For(1, 21, (i, state) =>
{
//類比工作
Thread.Sleep(700);
//輸出:迭代個數,線程ID和LowestBreakIteration
Console.WriteLine("迭代 {0} 線程 {1} LowestBreakIteration {2}",
i,
Thread.CurrentThread.ManagedThreadId,
state.LowestBreakIteration);
if (i == 1)
state.Break();
Interlocked.Increment(ref count);
});
Console.WriteLine("執行次數:{0}", count);
我得到了如下輸出:
迭代 6 線程 3 LowestBreakIteration
迭代 16 線程 5 LowestBreakIteration
迭代 2 線程 6 LowestBreakIteration
迭代 1 線程 1 LowestBreakIteration
迭代 11 線程 4 LowestBreakIteration
迭代 3 線程 6 LowestBreakIteration 1
迭代 17 線程 5 LowestBreakIteration 1
迭代 7 線程 3 LowestBreakIteration 1
執行次數:8
當3, 17, 7執行時,Break方法被調用,所以LowestBreakIteration為調用Break的最小迭代數,就是本例中的1。