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