I\'d like to make a request to X different web services who will each return either true
or false
.
These tasks should be executed in parall
One option is to use Reactive Extensions. Lets assume that you have a collection of tasks. It could be the tasks you mentioned in the question:
var tasks = new[] { t1, t2, t3 };
To execute the tasks in parallel and returning when the first tasks returns true
you use this expression:
var result = await tasks
.Select(t => t.ToObservable())
.Merge()
.FirstOrDefaultAsync(success => success);
The tasks are converted into observable sequences that each "fire" once when the task completes. These sequences are then merged into a single sequence which then is "converted" back into something that can be awaited using a predicate. And if necessary you can use a more complicated predicate instead of success => success
.
After this you can cancel the remaining unfinished tasks if you are using a CancellationTokenSource
:
cts.Cancel();
The variable result
will now be either true
or false
and any remaining tasks have been given a signal to cancel.
If you want to test this with your sample tasks you will have to modify them slightly to use Task.Delay
instead of Thread.Sleep
to enable the task to be cancelled:
var t1 = Task.Run<bool>(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(1), cts.Token);
Console.WriteLine("Task 1 Excecuted");
return false;
}, cts.Token);
You can simply use Task.WhenAny
and a predicate multiple times until the "right" task comes along
async Task<T> WhenAny<T>(IEnumerable<Task<T>> tasks, Func<T, bool> predicate)
{
var taskList = tasks.ToList();
Task<T> completedTask = null;
do
{
completedTask = await Task.WhenAny(taskList);
taskList.Remove(completedTask);
} while (!predicate(await completedTask) && taskList.Any());
return completedTask == null ? default(T) : await completedTask;
}