为了账号安全,请及时绑定邮箱和手机立即绑定

为复杂的 Task.WhenAll 添加超时

为复杂的 Task.WhenAll 添加超时

C#
ibeautiful 2022-12-24 09:51:58
我有一个运行异步任务的任务收集器(评论的那个):public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks){    return Task.WhenAll(        tasks.Select(            task => task.ContinueWith(                t => t.IsFaulted                    ? new ResultOrException<T>(t.Exception)                    : new ResultOrException<T>(t.Result))));       }public class ResultOrException<T>{    public ResultOrException(T result)    {        IsSuccess = true;        Result = result;    }    public ResultOrException(Exception ex)    {        IsSuccess = false;        Exception = ex;    }    public bool IsSuccess { get; }    public T Result { get; }    public Exception Exception { get; }} 此代码等待所有任务,即使它们在 2 分钟后返回。我需要忽略所有超时为五秒的任务返回。我也试过以这种方式更改我的代码,但它不会编译:return Task.WhenAny(Task.WhenAll(    tasks.Select(            task => task.ContinueWith(                t => t.IsFaulted                    ? new ResultOrException<T>(t.Exception)                    : new ResultOrException<T>(t.Result)))    ), Task.Delay(2000));或这个:var ts = new TimeSpan(1000);        return await Task.WaitAll(            tasks.Select(                task => task.ContinueWith(                    t => t.IsFaulted                        ? new ResultOrException<T>(t.Exception)                        : new ResultOrException<T>(t.Result))),            ts);如何做到这一点?
查看完整描述

1 回答

?
慕标琳琳

TA贡献1830条经验 获得超9个赞

它不会编译


这是因为Task.Delay返回一个Task. 那里没有价值或例外。所以它不能直接与ResultOrException<T>.


您需要决定如何向呼叫者报告超时。如果你想要Task<ResultOrException<T>[]>错误,那么你可以这样做:


public async Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)

{

    var resultOrExceptions = Task.WhenAll(

        tasks.Select(task => ...)

    );

    var delayTask = Task.Delay(2000);

    var completedTask = await Task.WhenAny(resultOrExceptions, delayTask);

    if (completedTask == delayTask)

        throw new TimeoutException();

    return await resultOrExceptions;

}

或者,如果你想返回一个数组ResultOrException<T>,每个数组都有超时错误,那么你可以这样做:


public async Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)

{

    var resultOrExceptionTasks = tasks.Select(task => ...)

        .ToArray();

    var resultOrExceptions = Task.WhenAll(resultOrExceptionTasks);

    var delayTask = Task.Delay(2000);

    var completedTask = await Task.WhenAny(resultOrExceptions, delayTask);

    if (completedTask == delayTask)

        return Enumerable.Repeat(new ResultOrException<T>(new TimeoutException()), resultOrExceptionTasks.Length).ToArray();

    return await resultOrExceptions;

}

或者,如果您想返回及时到达的结果,并且只返回那些没有及时到达的结果的超时异常,那么您想要将内部WhenAny 移动WhenAll:


public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)

{

    var delayTask = Task.Delay(2000);

    return Task.WhenAll(tasks.Select(WithTimeout));


    async Task<ResultOrException<T>> WithTimeout(Task<T> task)

    {

        var completedTask = await Task.WhenAny(task, delayTask);

        if (completedTask == delayTask)

            return new ResultOrException<T>(new TimeoutException());

        try

        {

            return new ResultOrException<T>(await task);

        }

        catch (Exception ex)

        {

            return new ResultOrException<T>(ex);

        }

    }

}

旁注:您应该始终将 a 传递TaskSchedulerContinueWith. 另外,我有一个可能有用的Try实现。


查看完整回答
反对 回复 2022-12-24
  • 1 回答
  • 0 关注
  • 155 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信