2

代碼始終等待,直到OperationCancelledException被引發之前當前正在運行的任務已完成。ParallelFor當條件滿足時不立即取消所有線程

我希望程序在條件成立時立即停止。

static void Main() 
{ 
    // want to break out of a Parallel.For immediately when a condition occurs 
    var cts = new CancellationTokenSource(); 
    var po = new ParallelOptions(); 
    po.CancellationToken = cts.Token; 

    long counterTotal = 0; 

    try 
    { 
     // want to have a sum of counts at the end 
     Parallel.For<long>(1, 26, po,() => 0, delegate(int i, ParallelLoopState state, long counterSubtotal) 
       { 
        po.CancellationToken.ThrowIfCancellationRequested(); 
        Console.WriteLine(i.ToString()); 

        for (int k = 0; k < 1000000000; k++) 
        { 
         counterSubtotal++; 

         if (i == 4 && k == 900000000) 
         { 
          cts.Cancel(); 
          // Would like to break out here immediately 
         } 
        } 

        return counterSubtotal; 
       }, (x) => Interlocked.Add(ref counterTotal, x) 
      ); 
    } 
    catch (OperationCanceledException e) 
    { 
     Console.WriteLine("Cancelled"); 
     Console.WriteLine("Total iterations across all threads {0}", String.Format("{0:n0}", counterTotal)); 
     Console.ReadLine(); 
    } 
} 

我發現把一個斷點cts.Cancel()和漁獲證明發生了什麼。

也看過state.Stop

這是其他代碼的簡化版本。

或許Parallel.For對於那些在方法內部運行很久的東西,如果我們想要立即突破,可能不太理想。

UPDATE2: 代碼現在可以按預期並給出了一個很好的總

static void Main() 
{ 
    // want to break out of a Parallel.For immediately when a condition occurs 
    var cts = new CancellationTokenSource(); 
    var po = new ParallelOptions(); 
    po.CancellationToken = cts.Token; 

    long counterTotal = 0; 

    try 
    { 
     // want to have a sum of counts at the end 
     // using type param here to make counterSubtotal a long 
     Parallel.For<long>(1, 26, po,() => 0, delegate(int i, ParallelLoopState state, long counterSubtotal) 
       { 
        Console.WriteLine(i.ToString()); 
        // 1 billion 
        for (int k = 0; k < 1000000000; k++) 
        { 
         //po.CancellationToken.ThrowIfCancellationRequested(); 
         if (po.CancellationToken.IsCancellationRequested) 
         { 
          return counterSubtotal; 
         } 
         counterSubtotal++; 

         if (i == 4 && k == 400000000) 
         { 
          Console.WriteLine("Inner Cancelled"); 
          cts.Cancel(); 
         } 
        } 
        return counterSubtotal; 
       }, (x) => Interlocked.Add(ref counterTotal, x) 
      ); 
    } 
    catch (OperationCanceledException e) 
    { 
     Console.WriteLine("Cancelled"); 
     Console.WriteLine("Total iterations across all threads {0}", String.Format("{0:n0}", counterTotal)); 
     Console.ReadLine(); 
    } 
} 

回答

3

如果你想讓它打破更多的「立即」比你需要檢查取消標記你內心裏面的。現在,它將在進入之前檢查取消,但在此之後它不會再次查看令牌。

for (int k = 0; k < 1000000000; k++) 
{ 
    po.CancellationToken.ThrowIfCancellationRequested(); 
    counterSubtotal++; 

    if (i == 4 && k == 900000000) 
    { 
     cts.Cancel(); 

    } 
} 
+0

謝謝pstrjds。請參閱上面我的代碼中的update2! – 2013-05-02 20:04:23