Task.WhenAny Grab Only Task, которая решает самый быстрый - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть два асинхронных метода, которые оба возвращают список.Они оба ищут записи по-разному, и мне нужно, чтобы они оба работали параллельно, и я забочусь только о задаче, которая заканчивается первой.Другой должен быть отменен, если это возможно.

Я предполагаю, что должен использовать Task.WhenAny, но, похоже, реализация не корректна.Приведенная ниже реализация GoAsync не возвращает никаких записей, она выпрыгивает из процедуры (без ошибок) в строке await Task.WhenAny (taskList).Я не получаю результатов и т. Д. Как я могу получить результаты?Правильно ли я это делаю?

public static async void GoAsync(SearchContract search, CancellationToken cancellationToken = default(CancellationToken))
        {
            var taskList = new List<Task>();

            taskList.Add(new Task(async () => await SearchRoutine1Async(search, cancellationToken)));
            taskList.Add(new Task(async () => await SearchRoutine2Async( search, cancellationToken)));

            Task completedTask = await Task.WhenAny(taskList);
        }

Асинхронные процедуры выглядят примерно так:

 public static async Task<List<SearchModel>> SearchRoutine1Async( SearchContract search, CancellationToken cancellationToken = default(CancellationToken))
        {
            using (DBContext db = new DBContext)
            {
                var searchModels= await db.SearchModel
                    .Where(sm => sm.subKey1 = search.subKey1)
                    .ToListAsync(cancellationToken)
                    ; 

                return searchModels;
            }
        }

Когда я пробовал запускать эти задачи по отдельности, например:.

var callTask = Task.Run(() => SearchRoutine1Async(search));
callTask.Wait();
var list1 = callTask.Result;

var callTask2 = Task.Run(() => SearchRoutine2Async(search));
callTask2.Wait();
var list2 = callTask.Result;

[ОБНОВЛЕНИЕ]: Я изменил свой GoAsync на это: согласно одному из ответов ниже: (но он все еще не работает)

public static async Task<List<SearchModel>> GoAsync(SearchContract search, CancellationToken cancellationToken = default(CancellationToken))
        {

            var taskList = new List<Task<List<SearchModel>>>
            {                    
                SearchRoutine1Async(search, cancellationToken),
                SearchRoutine2Async(search, cancellationToken)
            };

            Task<List<SearchModel>> completedTask = await Task.WhenAny(taskList);

            return completedTask.Result;
        }

Я звонюподпрограмма из СИНХРОННОЙ подпрограммы как таковая:

var result = GoAsync(search);

Обратите внимание, я глубоко в подпрограмме, где мне нужно выполнить эту задачу параллельно, чтобы получить конкурирующий результат.Эта подпрограмма как подпись приватной статической пустоты DoVariousCalucualtions () {}

1 Ответ

0 голосов
/ 27 ноября 2018

Вам не нужно создавать new Task, асинхронный метод вернет задачу.

public static async Task GoAsync(
    SearchContract search,
    CancellationToken cancellationToken = default(CancellationToken))
{
    var taskList = new List<Task<List<SearchModel>>>
    {
        SearchRoutine1Async(search, cancellationToken),
        SearchRoutine2Async( search, cancellationToken)
    };

    Task<List<SearchModel>> completedTask = await Task.WhenAny(taskList);
    // use competedTask.Result here (safe as you know task is completed)
}

После обновления вопроса:

Чтобы получить результаты, вам нужно дождаться, пока функцияcomplete.

var result = await GoAsync();

Но вы упомянули, что этот вызов находится глубоко в синхронной функции с подписью void, и вы не используете ASP.Net Core.Это означает, что вам нужно сделать весь «конвейер методов» асинхронным, начиная с действия контроллера.Если вы будете использовать GoAsync().Result;, вы получите тупик, поведение, которое вы уже испытали ...

...