Проблема с AWAIT / ASYNC и WebAPI с FOREACH

#c# #asp.net-web-api #async-await

#c# #asp.net-web-api #async-ожидание

Вопрос:

У меня есть несколько async методов, которые возвращают один и тот же тип из разных вызовов REST Api на основе OAuth.

Если я вызову его напрямую, я смогу получить данные обратно:

 //Call a specific provider
public async Task<List<Contacts>> Get()
{
    return await Providers.SpecificProvider.GetContacts();
}
 

Однако, если я попытаюсь перебрать несколько учетных записей, объект возвращается до AWAIT завершения:

 //Call all providers
public async Task<List<Contacts>> Get()
{
    return await Providers.GetContactsFromAllProviders();
}

public async Task<List<Contacts>> GetContactsFromAllProviders()
{
    var returnList = new List<Contacts>();
    //Providers inherits from List<>, so it can be enumerated to trigger
    //all objects in the collection
    foreach (var provider in Providers)
    {
        var con = await provider.GetContacts();
        returnList.Add(con);
    }
    return returnList;
}
 

Я новичок async и, вероятно, упускаю что-то простое

Комментарии:

1. Другая ситуация. У него уже есть решение для другого типа цикла, и он ищет эффективность.

2. async Ключевое слово в первом методе является избыточным. Вы можете просто return Providers.SpecificProvider.GetContacts();

Ответ №1:

Предоставленный вами код будет последовательно вызывать веб-службу для каждого поставщика по очереди. Я не понимаю, как ваше утверждение, которое объект возвращает до завершения ожидания, может быть истинным, потому что внутри цикла ожидается вызов GetContacts .

Однако вместо последовательного вызова поставщиков вы можете вызывать их параллельно, что в большинстве случаев должно сократить время выполнения:

 var tasks = providers.Select(provider => provider.GetContacts());

// Tasks execute in parallel - wait for them all to complete.
var result = await Task.WhenAll(tasks);

// Combine the returned lists into a single list.
var returnList = result.SelectMany(contacts => contacts).ToList();
 

Комментарии:

1. returnList.Add вызывается, но список возвращаемых данных уже был возвращен до того, как в него были добавлены все элементы.

2. await Task.WhenAll(tasks) было бы более эффективно, верно?

3. @MattJohnson: Да, вы правы. Я соответствующим образом обновил код.

4. @Wesley, возвращается задача, которая после завершения будет иметь returnList .