Reputation: 3080
I'm looking to use an array of Tasks
to find a solution to a problem using multiple methods. The idea being that I use a different Task
for each method. Is there a way to do a Tasks.WaitFirst(task => task.Result == true)
? Any solutions I've found so far have been very messy, I'm thinking of scrapping the idea but want to check I'm not missing something!
Thanks!
Upvotes: 0
Views: 80
Reputation: 117174
You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive
and add using System.Reactive.Linq;
- then you can do this:
void Main()
{
var query =
from n in Observable.Range(0, 25)
from v in Observable.FromAsync(() => GetValueAsync())
select v;
query.Take(1).Subscribe(x => Console.WriteLine(x));
}
private Random _random = new Random();
public async Task<int> GetValueAsync()
{
var value = _random.Next(5, 100);
Console.WriteLine($"!{value}");
await Task.Delay(TimeSpan.FromSeconds(value));
return value;
}
You basically end up with a simple query that you can use .Take(1)
to get the first value to finish. It's nice a clean and simple.
If you post how you are creating the tasks then I can post a complete answer.
Upvotes: 2
Reputation: 3508
I don't think this is something that this is in .net, but you can write your own version. Somethin like this
public static async Task<T> WhenFirst<T>(IEnumerable<Task<T>> tasks, Func<T, bool> predicate)
{
var taskArray = tasks.ToArray();
var completedTask = await Task.WhenAny(taskArray);
if (predicate(await completedTask))
{
return await completedTask;
}
else
{
var notCompletedTasks = new List<Task<T>>();
foreach(var task in taskArray)
{
if (task.IsCompleted && predicate(await task)) return await task;
else notCompletedTasks.Add(task);
}
return await WhenFirst(notCompletedTasks, predicate);
}
}
Upvotes: 0