4

我正在实现一个 Parallel.ForEach 循环来做一些工作,但是由于未处理的异常,我遇到了一个问题,而我认为我处理了取消。

为了解决这个问题,我在 winform 中做了一个简单的测试设置。它有一个开始按钮、一个取消按钮和一个输出标签。

编码:

public partial class Form1 : Form
{
    CancellationTokenSource cts = new CancellationTokenSource();

    public Form1()
    {
        InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        output.Text = "Running";

        try
        {
            var runTask = Task<string>.Factory.StartNew(() => Run());
            await runTask;
            this.output.Text = runTask.Result;
        }
        catch(Exception ex)
        {
            throw ex;
        }
    }

    private string Run()
    {
        int useThreads = Environment.ProcessorCount - 2 < 1 ? 1 : Environment.ProcessorCount - 2;

        ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = useThreads, CancellationToken = cts.Token };

        options.CancellationToken.Register(() => ActionOnCancel());

        List<int> somelist =new List<int>();

        for(int i = 0; i < 100; i++)
            somelist.Add(i);

        Parallel.ForEach(somelist, options, (row, loopstate) =>
        {
            if(loopstate.ShouldExitCurrentIteration || loopstate.IsExceptional)
                loopstate.Stop();

            Thread.Sleep(1000);

        });

        return "Done";
    }

    private void ActionOnCancel()
    {
        output.Text= "Cancelled";
    }

    private void button2_Click(object sender, EventArgs e)
    {
        cts.Cancel();
    }

当我运行程序并点击取消按钮(触发 button2_Click)时,我不断收到此错误:

mscorlib.dll 中出现“System.OperationCanceledException”类型的异常,但未在用户代码中处理

附加信息:操作已取消。

如果有这个异常的处理程序,程序可以安全地继续。

调试器突出显示 Parallel.ForEach 部分。但为什么???我以为我通过 CancellationToken 正确处理了取消。

ex 中的异常消息并没有让我清楚:“{“操作被取消。”}”呃......是的......这就是意图......

我在看什么?问候,

马蒂斯

4

2 回答 2

8

总是抛出这个异常。如果在 CancellationTokenSource 上调用了取消方法,则在访问并行任务时必须处理 OperationCanceledException。

try
{
    Parallel.ForEach(somelist, options, (row, loopstate) =>
    {
        if(loopstate.ShouldExitCurrentIteration || loopstate.IsExceptional)
            loopstate.Stop();

        Thread.Sleep(1000);

    });
}
catch (OperationCanceledException)
{
    // Handle the cancelled Task
}
于 2012-12-14T15:43:45.247 回答
1

CancellationToken.Register() 提供了一种向取消添加回调的方法,但不会“处理”它,就 OperationCanceledException 而言。

我建议您在 Run() 方法中也放置一个 try/catch 块。

于 2012-12-14T15:41:29.050 回答