gpt4 book ai didi

c# - 优雅地处理任务取消

转载 作者:IT王子 更新时间:2023-10-29 04:09:44 30 4
gpt4 key购买 nike

当我将任务用于我需要能够取消的大型/长时间运行的工作负载时,我经常使用类似于此的模板来执行任务执行的操作:

public void DoWork(CancellationToken cancelToken)
{
try
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
Log.Exception(ex);
throw;
}
}

OperationCanceledException不应记录为错误,但如果任务要转换为已取消状态,则不得被吞噬。超出此方法范围的任何其他异常都不需要处理。

这总是感觉有点笨拙,默认情况下 visual studio 会在抛出 OperationCanceledException 时中断(虽然我现在为 OperationCanceledException 关闭了“用户未处理中断”,因为我使用了这种模式)。

更新:现在是 2021 年,C#9 给了我一直想要的语法:

public void DoWork(CancellationToken cancelToken)
{
try
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
Log.Exception(ex);
throw;
}
}
<罢工>理想情况下,我想我希望能够做这样的事情:
public void DoWork(CancellationToken cancelToken)
{
try
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
catch (Exception ex) exclude (OperationCanceledException)
{
Log.Exception(ex);
throw;
}
}
即,将某种排除列表应用于 catch,但没有当前不可能的语言支持(@eric-lippert:c# vNext 功能 :))。

另一种方法是通过延续:

public void StartWork()
{
Task.Factory.StartNew(() => DoWork(cancellationSource.Token), cancellationSource.Token)
.ContinueWith(t => Log.Exception(t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
}

public void DoWork(CancellationToken cancelToken)
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}

但我不太喜欢这样,因为从技术上讲,异常可能有多个内部异常,并且在记录异常时您没有像第一个示例中那样多的上下文(如果我做的不止一个)只是记录它)。

我知道这有点风格问题,但想知道是否有人有更好的建议?

我是否只需要坚持示例 1?

最佳答案

那么,问题是什么?只需丢弃 catch (OperationCanceledException) block ,并设置适当的延续:

var cts = new CancellationTokenSource();
var task = Task.Factory.StartNew(() =>
{
var i = 0;
try
{
while (true)
{
Thread.Sleep(1000);

cts.Token.ThrowIfCancellationRequested();

i++;

if (i > 5)
throw new InvalidOperationException();
}
}
catch
{
Console.WriteLine("i = {0}", i);
throw;
}
}, cts.Token);

task.ContinueWith(t =>
Console.WriteLine("{0} with {1}: {2}",
t.Status,
t.Exception.InnerExceptions[0].GetType(),
t.Exception.InnerExceptions[0].Message
),
TaskContinuationOptions.OnlyOnFaulted);

task.ContinueWith(t =>
Console.WriteLine(t.Status),
TaskContinuationOptions.OnlyOnCanceled);

Console.ReadLine();

cts.Cancel();

Console.ReadLine();

TPL区分取消和故障。因此,取消(即在任务主体内抛出 OperationCancelledException)不是错误

要点:不要处理任务体内的异常而不重新抛出它们。

关于c# - 优雅地处理任务取消,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12633903/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com