我正在实现一个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中的异常消息并没有给我任何清晰的说明:“{”操作被取消了。“}”呃......是的......这是意图......
我在俯瞰什么? 的问候,
Matthijs
答案 0 :(得分:8)
始终抛出此异常。如果在CancellationTokenSource上调用cancel方法,则必须在访问Parallel Tasks时处理OperationCanceledException。
try
{
Parallel.ForEach(somelist, options, (row, loopstate) =>
{
if(loopstate.ShouldExitCurrentIteration || loopstate.IsExceptional)
loopstate.Stop();
Thread.Sleep(1000);
});
}
catch (OperationCanceledException)
{
// Handle the cancelled Task
}
答案 1 :(得分:1)
CancellationToken.Register()提供了一种方法,可以根据OperationCanceledException将回调添加到取消中,但不会“处理”它。
我建议你在Run()方法中放置一个try / catch块。