c# - 取消 token 在这里有什么用

标签 c# .net task-parallel-library task resharper

我有以下代码块:

using (var cancelSource = new CancellationTokenSource()) 
{
    Task[] tasks = null;

    var cancelToken = cancelSource.Token;
    tasks = new[]
    {
        Task.Run(async () => await ThrowAfterAsync("C", cancelToken, 1000)) //<---
    };
    await Task.Delay(howLongSecs * 1000); // <---
    cancelSource.Cancel();
    await Task.WhenAll(tasks);
}

ThrowAfterAsync 有这个:

private async Task ThrowAfterAsync(string taskId, CancellationToken cancelToken, int afterMs)
{
    await Task.Delay(afterMs, cancelToken);
    var msg = $"{taskId} throwing after {afterMs}ms";
    Console.WriteLine(msg);
    throw new ApplicationException(msg);
}

Resharper 建议我可以像这样使用带有取消 token 的 Task.Run() 重载:

Task.Run(async () => await ThrowAfterAsync("C", cancelToken, 1000), cancelToken)

但为什么呢?在没有取消标记作为参数的情况下,在第一个版本上这样做有什么好处?

最佳答案

在这种特定情况下,没有意义。一般来说,你会想按照它的建议去做,因为通过将 token 传递给 Task.Run 如果 token 在操作完成之前被取消,它甚至可以避免首先安排操作有机会开始,但在您的情况下,您正在创建 token 并且您知道它不会在您开始操作时被取消。

但是您不需要将 token 传递给 Task.Run 的原因是因为启动该任务的代码是负责取消 token 的操作,并且所以它知道 token 尚未取消。通常您会从其他地方接受 token ,并且您不知道它是否/何时被取消。

综上所述,根本没有理由使用 Task.Run 。你可以只写:

tasks = new[] { ThrowAfterAsync("C", cancelToken, 1000) };

它将具有相同的行为,但不会为了启动异步操作而不必要地启动一个新线程。

接下来,您的代码永远不会在少于 howLongSecs 内返回,即使操作在此之前完成,因为您构建代码的方式。您应该简单地向取消 token 源提供超时并让它在正确的时间取消 token ,如果操作在取消应该发生之前完成,它不会延迟您的方法的其余部分,因此您的整个方法可以只需写成:

using (var cancelSource = new CancellationTokenSource(Timespan.FromSeconds(howLongSecs))) 
{
    await ThrowAfterAsync("C", cancelToken, 1000)
}

关于c# - 取消 token 在这里有什么用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41400544/

相关文章:

c# - 无法将字符串值转换为日期时间,包括毫秒

c# - Task.Factory.StartNew 保证执行顺序

.net - 任务结果评估的时间安排

c# - LINQ GroupBy - 按名称选择最低 ID 组

c# - 为什么使用 Angular 模板的 .Net Core Web 应用程序需要安装 NodeJs?

c# - 无法在 ASP.Net vNext 项目中使用 session

asp.net - 在 .NET Core 2.0 中显示 json 数据的问题

javascript - 如何点击非静态页面(webbrowser c#)中的输入按钮?

c# - ASP.net 从 URL 加载 XML 文件

c# - 如何观察由于 C# 中另一个等待任务失败而未等待的任务?