我正在开发一个应用程序,在该应用程序中,尽快将数据返回到串行进程很重要,但可以有多个来源来获取该数据。同样,有时一个来源比另一个更快,但您不知道会是哪个来源。我正在使用 ContinueWhenAny(...).Wait() 等待第一个任务结束,以便继续并退出调用方法。但是,我需要先检查数据的有效性,然后才返回(或者如果所有任务都已完成并且它们都没有有效数据)。现在,如果这是首先完成的任务,我的代码甚至会返回无效数据。
有没有办法做类似“ContinueWhenAny”的事情,但只有当Task.Result满足某个条件时,否则等待下一个任务/等......直到最后一个任务完成?
同样,我需要确保在一个结果有效后,其他线程取消。这部分已经运行良好。
目前,我的代码看起来像这样(去掉了异常处理,只是细节):
ResultObject result = null;
var tokenSource = new CancellationTokenSource();
var tasks = listOfSources
.Select(i => Task.Factory.StartNew(
() =>
{
i.CancellationToken = tokenSource.Token;
//Database Call
return i.getData(inputparameters);
}, tokenSource.Token));
Task.Factory.ContinueWhenAny(
tasks.ToArray(),
firstCompleted =>
{
//This is the "result" I need to validate before setting and canceling the other threads
result = firstCompleted.Result;
tokenSource.Cancel();
}).Wait();
return result;
有任何想法吗?我不想使用 ContinueWhenAll 因为如果第一次调用需要 2 秒,第二次需要 10 秒,如果第一次调用返回有效数据,我想在 2 秒内返回串行过程,否则等待 10 秒,希望result 有有效数据,只有在所有任务都完成并返回无效结果时才返回无效数据。
--------- 更新 ---- 感谢 zmbq 的好主意。更新的(工作)代码如下,满足我的所有要求。但是需要注意的是,此代码与前面代码之间的区别在于,如果没有任何任务产生有效结果,则此代码将返回 null 结果,而不是前面代码本身返回无效结果。更改此版本也不会很困难,但是出于我的目的,在这种情况下我完全满足于返回 null 。
ResultObject result = null;
var tokenSource = new CancellationTokenSource();
var tasks = listOfSources
.Select(i => Task.Factory.StartNew(
() =>
{
i.CancellationToken = tokenSource.Token;
//Database Call
return i.getData(inputparameters);
}, tokenSource.Token)).ToArray();
result = GetFirstValidResult(tokenSource,tasks);
return result;
private ResultObject GetFirstValidResult(CancellationTokenSource tokenSource, Task<ResultObject>[] tasks)
{
ResultObject result = null;
Task.Factory.ContinueWhenAny(
tasks,
firstCompleted =>
{
var testResult = firstCompleted.Result;
if(testResult != null && testResult.IsValid())
{
result = testResult;
tokenSource.Cancel();
}
else
{
var remainingTasks = tasks.Except(new[]{firstCompleted}).ToArray();
if(remainingTasks.Any())
{
result = GetFirstValidResult(tokenSource, remainingTasks);
}
}
}).Wait();
return result;
}