在我的 C# 控制台应用程序中,我试图运行多个同时执行各种数据检查的任务。 如果其中一项任务返回真值,我应该停止其他任务,因为我得到了可操作的结果。也很可能没有函数返回 true
我有一起运行这些任务的代码(我想),我只是在到达终点线时遇到了问题:
Task task1 = Task.Run(() => Task1(stoppingToken));
Task task2 = Task.Run(() => Task2(stoppingToken));
Task task3 = Task.Run(() => Task3(stoppingToken));
Task task4 = Task.Run(() => Task4(stoppingToken));
Task task5 = Task.Run(() => Task5(stoppingToken));
Task task6 = Task.Run(() => Task6(stoppingToken));
Task.WaitAll(task1, task2, task3, task4, task5, task6);
这与已知所需结果(超时值)的链接问题中的答案略有不同。我正在等待这些任务中的任何一个可能返回 true,然后取消剩余的任务(如果它们仍在运行)
Task.WhenAny with cancellation of the non completed tasks and timeout
最佳答案
这是一个基于连续任务的解决方案。这个想法是将延续任务附加到每个原始(提供的)任务,并在那里检查结果。如果匹配,则完成源将设置一个结果(如果没有匹配,则根本不会设置结果)。
然后,代码将等待最先发生的事情:要么所有延续任务完成,要么设置任务完成结果。无论哪种方式,我们都准备好检查与任务完成源关联的任务的结果(这就是为什么我们等待后续任务完成,而不是原始任务),如果已设置,则它是几乎表明我们有一场比赛(最后的额外检查有点偏执,但我猜比抱歉更安全......:D)
public static async Task<bool> WhenAnyHasResult<T>(Predicate<T> isExpectedResult, params Task<T>[] tasks)
{
const TaskContinuationOptions continuationTaskFlags = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent;
// Prepare TaskCompletionSource to be set only when one of the provided tasks
// completes with expected result
var tcs = new TaskCompletionSource<T>();
// For every provided task, attach a continuation task that fires
// once the original task was completed
var taskContinuations = tasks.Select(task =>
{
return task.ContinueWith(x =>
{
var taskResult = x.Result;
if (isExpectedResult(taskResult))
{
tcs.SetResult(taskResult);
}
},
continuationTaskFlags);
});
// We either wait for all the continuation tasks to be completed
// (it's most likely an indication that none of the provided tasks completed with the expected result)
// or for the TCS task to complete (which means a failure)
await Task.WhenAny(Task.WhenAll(taskContinuations), tcs.Task);
// If the task from TCS has run to completion, it means the result has been set from
// the continuation task attached to one of the tasks provided in the arguments
var completionTask = tcs.Task;
if (completionTask.IsCompleted)
{
// We will check once more to make sure the result is set as expected
// and return this as our outcome
var tcsResult = completionTask.Result;
return isExpectedResult(tcsResult);
}
// TCS result was never set, which means we did not find a task matching the expected result.
tcs.SetCanceled();
return false;
}
现在,用法如下:
static async Task ExampleWithBooleans()
{
Console.WriteLine("Example with booleans");
var task1 = SampleTask(3000, true);
var task2 = SampleTask(5000, false);
var finalResult = await TaskUtils.WhenAnyHasResult(result => result == true, task1, task2);
// go ahead and cancel your cancellation token here
Console.WriteLine("Final result: " + finalResult);
Debug.Assert(finalResult == true);
Console.WriteLine();
}
将它放入泛型方法的好处在于,作为原始任务的结果,它适用于任何类型,而不仅仅是 bool 值。
关于c# - 有没有办法等待所有任务直到特定结果为真,然后取消其余的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68749441/