Чтобы упростить задачу, вы должны сначала изменить свой GetInsuranceByANI
метод, чтобы снова стать синхронным. Позже мы будем вызывать задачи для асинхронного вызова.
public IEnumerable<Insurance> GetInsuranceByANI(string ani)
{
using (ITransaction transaction = Session.Value.BeginTransaction())
{
transaction.Rollback();
IDbCommand command = new SqlCommand();
command.Connection = Session.Value.Connection;
transaction.Enlist(command);
string storedProcName = "spGetInsurance";
command.CommandText = storedProcName;
command.Parameters.Add(new SqlParameter("@ANI", SqlDbType.Char, 0, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, ani));
var rdr = command.ExecuteReader();
return MapInsurance(rdr);
}
}
Теперь к реализации метода, который ищет все базы данных асинхронно. Мы создадим задачу для каждой базы данных, работающей в потоке пула потоков. Это спорно, но мы пытаемся держать вещи простыми. Мы также создаем экземпляр CancellationTokenSource
и передаем его Token
всем Task.Run
методам. Это только гарантирует, что после того, как мы получим наш результат, больше никаких задач не начнется. Если доступные потоки в пуле потоков больше, чем базы данных для поиска, все задачи начнутся немедленно, и маркер отмены фактически ничего не отменит. Другими словами, все запущенные запросы будут выполнены независимо от того, что. Это, очевидно, пустая трата ресурсов, но, опять же, мы пытаемся упростить ситуацию.
После запуска задач мы входим в цикл, ожидающий завершения следующей задачи (используя метод Task.WhenAny
). Если результат найден, мы отменяем токен и возвращаем результат. Если результат не найден, мы продолжаем цикл для следующего результата. Если все задачи завершены, а у нас по-прежнему нет результата, мы возвращаем ноль.
async Task<IEnumerable<Insurance>> SearchAllByANI(string ani)
{
var tasks = new HashSet<Task<IEnumerable<Insurance>>>();
var cts = new CancellationTokenSource();
using (var Contexts = instContextfactory.GetContextList())
{
foreach (var context in Contexts.GetContextList())
{
tasks.Add(Task.Run(() =>
{
return context.Insurance.GetInsuranceByANI(ani);
}, cts.Token));
}
}
while (tasks.Count > 0)
{
var task = await Task.WhenAny(tasks);
var result = await task;
if (result != null && result.Any())
{
cts.Cancel();
return result;
}
tasks.Remove(task);
}
return null;
}
Пример использования:
IEnumerable<Insurance> result = await SearchAllByANI("12345");
if (result == null)
{
// Nothing fould
}
else
{
// Do something with result
}