为复杂的 Task.WhenAll 添加超时

我有一个运行异步任务的任务收集器(评论的那个):


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);

如何做到这一点?


ibeautiful
浏览 160回答 1
1回答

慕标琳琳

它不会编译这是因为Task.Delay返回一个Task. 那里没有价值或例外。所以它不能直接与ResultOrException<T>.您需要决定如何向呼叫者报告超时。如果你想要Task<ResultOrException<T>[]>错误,那么你可以这样做:public async Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks){&nbsp; &nbsp; var resultOrExceptions = Task.WhenAll(&nbsp; &nbsp; &nbsp; &nbsp; tasks.Select(task => ...)&nbsp; &nbsp; );&nbsp; &nbsp; var delayTask = Task.Delay(2000);&nbsp; &nbsp; var completedTask = await Task.WhenAny(resultOrExceptions, delayTask);&nbsp; &nbsp; if (completedTask == delayTask)&nbsp; &nbsp; &nbsp; &nbsp; throw new TimeoutException();&nbsp; &nbsp; return await resultOrExceptions;}或者,如果你想返回一个数组ResultOrException<T>,每个数组都有超时错误,那么你可以这样做:public async Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks){&nbsp; &nbsp; var resultOrExceptionTasks = tasks.Select(task => ...)&nbsp; &nbsp; &nbsp; &nbsp; .ToArray();&nbsp; &nbsp; var resultOrExceptions = Task.WhenAll(resultOrExceptionTasks);&nbsp; &nbsp; var delayTask = Task.Delay(2000);&nbsp; &nbsp; var completedTask = await Task.WhenAny(resultOrExceptions, delayTask);&nbsp; &nbsp; if (completedTask == delayTask)&nbsp; &nbsp; &nbsp; &nbsp; return Enumerable.Repeat(new ResultOrException<T>(new TimeoutException()), resultOrExceptionTasks.Length).ToArray();&nbsp; &nbsp; return await resultOrExceptions;}或者,如果您想返回及时到达的结果,并且只返回那些没有及时到达的结果的超时异常,那么您想要将内部WhenAny 移动WhenAll:public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks){&nbsp; &nbsp; var delayTask = Task.Delay(2000);&nbsp; &nbsp; return Task.WhenAll(tasks.Select(WithTimeout));&nbsp; &nbsp; async Task<ResultOrException<T>> WithTimeout(Task<T> task)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var completedTask = await Task.WhenAny(task, delayTask);&nbsp; &nbsp; &nbsp; &nbsp; if (completedTask == delayTask)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new ResultOrException<T>(new TimeoutException());&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new ResultOrException<T>(await task);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; catch (Exception ex)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new ResultOrException<T>(ex);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}旁注:您应该始终将 a 传递TaskScheduler给ContinueWith.&nbsp;另外,我有一个可能有用的Try实现。
打开App,查看更多内容
随时随地看视频慕课网APP