When I first saw this question I thought of
Reactive Extensions (Rx)[
^]
It took a while to get a chance to work it up, but here is an example where each
(proxy for a) query of the server/domain is done in parallel in a separate
Task
and Rx is used to wait for the first one that returns true. Once success happens, then the
CancellationToken
is used to notify any query that hasn't completed that it can quit. (I'm assuming that your verification method can use a
CancellationToken
to stop before completing.)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication7
{
class Program
{
static void Main(string[] args)
{
RunIt();
Console.ReadLine();
}
private class Result
{
public readonly int Id;
public bool Success { get; set; }
public Result(int id)
{
Id = id;
Success = false;
}
}
static async void RunIt()
{
CancellationTokenSource cancellationSource = new CancellationTokenSource();
CancellationToken token = cancellationSource.Token;
Random rand = new Random();
List<int> values = Enumerable.Range(0, 10).Select(_ => rand.Next(1, 30)).ToList();
Console.WriteLine("values=");
foreach (var item in values)
{
Console.WriteLine(item);
}
Console.WriteLine();
var observableValues = values.ToObservable();
var tasks = observableValues.Select(x => Task.Run<Result>(() => {
Console.WriteLine("Start " + x.ToString());
var res = new Result(x);
for (int i = 0; i < x; i++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancellation requested: {0}", x);
return res;
}
Thread.Sleep(1000);
}
Console.WriteLine("Task = " + x.ToString());
res.Success = (x & 1) != 0;
return res;
}, token));
Result found = await tasks.Merge().FirstOrDefaultAsync(r => r.Success);
cancellationSource.Cancel();
Console.WriteLine(found == null ? "None found" : ("Found " + found.Id.ToString()));
}
}
}