等待单个任务从List< Task<.>中失败.更干净,可能与LINQ有关? [英] Waiting for a single task to fail out of a List<Task<..>> more cleanly, possibly with LINQ?
问题描述
在我的应用程序中,我有一个List<Task<Boolean>>
,我可以通过Task.Wait[..]
来确定它们是否成功完成(Result = true
).虽然如果在等待期间Task
完成并返回了falsey值,但是我想取消所有其他Task
,则我正在等待并基于此进行操作.
In my application I have a List<Task<Boolean>>
that I Task.Wait[..]
on to determine if they completed successfully (Result = true
). Though if during my waiting a Task
completes and returns a falsey value I want to cancel all other Task
I am waiting on and do something based on this.
我创建了两个丑陋"的方法来实现这一目的
I have created two "ugly" methods to do this
// Create a CancellationToken and List<Task<..>> to work with
CancellationToken myCToken = new CancellationToken();
List<Task<Boolean>> myTaskList = new List<Task<Boolean>>();
//-- Method 1 --
// Wait for one of the Tasks to complete and get its result
Boolean finishedTaskResult = myTaskList[Task.WaitAny(myTaskList.ToArray(), myCToken)].Result;
// Continue waiting for Tasks to complete until there are none left or one returns false
while (myTaskList.Count > 0 && finishedTaskResult)
{
// Wait for the next Task to complete
finishedTaskResult = myTaskList[Task.WaitAny(myTaskList.ToArray(), myCToken)].Result;
if (!finishedTaskResult) break;
}
// Act on finishTaskResult here
// -- Method 2 --
// Create a label to
WaitForOneCompletion:
int completedTaskIndex = Task.WaitAny(myTaskList.ToArray(), myCToken);
if (myTaskList[completedTaskIndex].Result)
{
myTaskList.RemoveAt(completedTaskIndex);
goto WaitForOneCompletion;
}
else
;// One task has failed to completed, handle appropriately
我想知道是否有更清洁的方法(可能与LINQ一起使用)?
I was wondering if there was a cleaner way to do this, possibly with LINQ?
推荐答案
您可以使用以下方法来执行一系列任务,并创建一个新的任务序列,这些任务序列代表初始任务,但以它们全部完成的顺序返回:
You can use the following method to take a sequence of tasks and create a new sequence of tasks that represents the initial tasks but returned in the order that they all complete:
public static IEnumerable<Task<T>> Order<T>(this IEnumerable<Task<T>> tasks)
{
var taskList = tasks.ToList();
var taskSources = new BlockingCollection<TaskCompletionSource<T>>();
var taskSourceList = new List<TaskCompletionSource<T>>(taskList.Count);
foreach (var task in taskList)
{
var newSource = new TaskCompletionSource<T>();
taskSources.Add(newSource);
taskSourceList.Add(newSource);
task.ContinueWith(t =>
{
var source = taskSources.Take();
if (t.IsCanceled)
source.TrySetCanceled();
else if (t.IsFaulted)
source.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCompleted)
source.TrySetResult(t.Result);
}, CancellationToken.None, TaskContinuationOptions.PreferFairness, TaskScheduler.Default);
}
return taskSourceList.Select(tcs => tcs.Task);
}
现在,您可以根据任务的完成顺序对任务进行排序了,您可以基本上完全按照您的要求编写代码:
Now that you have the ability to order the tasks based on their completion you can write the code basically exactly as your requirements dictate:
foreach(var task in myTaskList.Order())
if(!await task)
cancellationTokenSource.Cancel();
这篇关于等待单个任务从List< Task<.>中失败.更干净,可能与LINQ有关?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!