Task.WhenAny - 一项任务被取消

SB2*_*055 4 .net c# task task-parallel-library async-await

在以下代码中:

        if (await Task.WhenAny(task, Task.Delay(100)) == task) {
            success = true;
        }
        else {
            details += "Timed out on SendGrid.";
            await task.ContinueWith(s =>
            {
                LogError(s.Exception);
            }, TaskContinuationOptions.OnlyOnFaulted);
        }
Run Code Online (Sandbox Code Playgroud)

我偶尔会A task was cancelled接到电话await task.ContinueWith.我的目标是看看是否task在100ms内完成 - 如果没有,我想处理一些日志记录(这个特定任务有资源泄漏,所以我试图通过将其包装在超时中来解决它).这是从这里的指导中提取的: Debugging Task.WhenAny和Push Notifications

为什么会发生这种情况,我该怎么做才能防止抛出此异常?

Evk*_*Evk 6

当你task无法及时完成时(100毫秒)但是能够在以后完成时会发生这种情况.TaskContinuationOptions.OnlyOnFaulted如果原始任务没有出现故障,则运行继续操作并取消此类任务.你await造成的ContinueWith,所以如果你的任务没有故障-你继续被取消,你有一个例外.

通常这种处理超时的方法没有多大意义,因为即使在达到超时之后,您仍然要等到原始任务完成,才能记录异常.我想你必须await在继续之前删除.然后代码将在超时时继续,但如果任务稍后失败 - 它将被记录.

您的代码中还有另一个问题 - Task.WhenAny永远不会抛出.所以这个条件:

await Task.WhenAny(task, Task.Delay(100)) == task
Run Code Online (Sandbox Code Playgroud)

并不意味着成功,因为task可能会出现问题.始终检查task.Status,task.Exception即使WhenAny表明您的任务已完成.顺便说一句,您在问题中链接的答案提到了这一点.

更新:如果您不喜欢关于未等待电话的VS警告 - 您可以为此特定行禁用它,或使用如下扩展方法:

static class TaskExtensions
{
    public static void Forget(this Task task)
    {
        // do nothing
    }
}
Run Code Online (Sandbox Code Playgroud)

然后:

task.ContinueWith(s => {
    Logger.Write(s.Exception);
}, TaskContinuationOptions.OnlyOnFaulted).Forget();
Run Code Online (Sandbox Code Playgroud)

这样做是没有害处的(当然在这个特殊情况下),VS只是在每个可能等待的等待的电话上发出这个警告.