我有一个运行异步任务(已注释的任务)的任务收集器:
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分钟后返回。 我需要忽略所有任务返回,超时为5秒。
我也尝试过以此方式更改代码,但无法编译:
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);
如何实现?
答案 0 :(得分:1)
它不会编译
这是因为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);
}
}
}
旁注:您应该always pass a TaskScheduler
to ContinueWith
。另外,我有一个Try
implementation可能会有用。