我创建了下面的函数,它会在发生取消或超时时等待所有任务完成或引发异常。

public static async Task WhenAll(
    IEnumerable<Task> tasks,
    CancellationToken cancellationToken,
    int millisecondsTimeOut)
{
    Task timeoutTask = Task.Delay(millisecondsTimeOut, cancellationToken);
    Task completedTask = await Task.WhenAny(
        Task.WhenAll(tasks),
        timeoutTask
    );
    if (completedTask == timeoutTask)
    {
        throw new TimeoutException();
    }
}

如果所有 tasks 在长时间超时之前完成(即 millisecondsTimeOut = 60,000),那么即使在函数返回之后 timeoutTask 会一直停留到 60 秒过去吗?如果是,解决失控问题的最佳方法是什么?

最佳答案

是的,timeoutTask 会一直存在,直到超时结束(或 CancellationToken 被取消)。

您可以通过传入从使用 CancellationToken 创建的新 CancellationTokenSource 获得的不同 CancellationTokenSource.CreateLinkedTokenSource 并在最后取消来修复它。您还应该等待已完成的任务,否则您并没有真正观察到异常(或取消):

public static async Task WhenAll(
    IEnumerable<Task> tasks,
    CancellationToken cancellationToken,
    int millisecondsTimeOut)
{
    var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
    var timeoutTask = Task.Delay(millisecondsTimeOut, cancellationTokenSource.Token);
    var completedTask = await Task.WhenAny(Task.WhenAll(tasks), timeoutTask);
    if (completedTask == timeoutTask)
    {
        throw new TimeoutException();
    }

    cancellationTokenSource.Cancel();
    await completedTask;
}

但是,如果您不需要区分 TimeoutExceptionTaskCancelledException ,我认为有一种更简单的方法可以实现您想要的。您只需添加一个在 CancellationToken 被取消或超时结束时被取消的延续:
public static Task WhenAll(
    IEnumerable<Task> tasks,
    CancellationToken cancellationToken,
    int millisecondsTimeOut)
{
    var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
    cancellationTokenSource.CancelAfter(millisecondsTimeOut);

    return Task.WhenAll(tasks).ContinueWith(
        _ => _.GetAwaiter().GetResult(),
        cancellationTokenSource.Token,
        TaskContinuationOptions.ExecuteSynchronously,
        TaskScheduler.Default);
}

关于c# - 结束任务以防止失控的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31885498/

10-12 20:04