【问题标题】:ParallelFor not cancelling all threads immediately if condition met如果条件满足,ParallelFor 不会立即取消所有线程
【发布时间】:2013-05-02 18:03:16
【问题描述】:

代码总是等到当前运行的任务完成后才会抛出 OperationCancelledException

我希望程序在条件为真时立即停止。

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() 上设置了一个断点,并且在 catch 中演示了正在发生的事情。

也看过state.Stop

这是其他代码的简化版本。

如果我们想立即突破,也许Parallel.For 不适合在方法中运行很长时间的事情。

更新 2: 代码现在可以按预期工作并给出一个很好的总数

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();
    }
}

【问题讨论】:

    标签: c# task-parallel-library parallel.foreach cancellationtokensource


    【解决方案1】:

    如果您希望它“立即”中断,而不是您需要检查内部的取消令牌。就像现在一样,它会在进入之前检查取消,但之后它不会再查看令牌。

    for (int k = 0; k < 1000000000; k++)
    {
        po.CancellationToken.ThrowIfCancellationRequested();
        counterSubtotal++;
    
        if (i == 4 && k == 900000000)
        {
           cts.Cancel();
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      相关资源
      最近更新 更多