Разница между "ToListAsync()" и "AsAsyncEnumerable().ToList()"
Функцию нужно вернуть Task<List<Record>>
После оба варианта возвращаются Task<List<Record>>
какой из них более эффективен? Есть ли здесь какой-нибудь стандартный способ?
Опция 1:
Task<List<Record>> GetRecords()
{
return
DbContext.Set<Record>.Where(predicate).ToListAsync();
}
Вариант 2:
Task<List<Record>> GetRecords()
{
return
DbContext.Set<Record>.Where(predicate).AsAsyncEnumerable().ToList();
}
3 ответа
Перейти на вариант 1 ToListAsync
в качестве исходного кода AsAsyncEnumerable
прямо упоминает
Это внутренний API, который поддерживает инфраструктуру Entity Framework Core и не подчиняется тем же стандартам совместимости, что и публичные API. Он может быть изменен или удален без предварительного уведомления в любом выпуске. Вы должны использовать его непосредственно в своем коде с особой осторожностью, зная, что это может привести к сбоям приложения при обновлении до новой версии Entity Framework Core.
Официальная документация упоминает
Этот API поддерживает инфраструктуру Entity Framework Core и не предназначен для использования непосредственно из вашего кода. Этот API может измениться или быть удален в будущих выпусках.
На самом деле никто не объяснил разницу между и .
извлечет все результаты запроса в память, а затем вернет набор результатов как одинList<T>
объект. Он будет делать это асинхронно, чтобы не блокировать ввод-вывод, но ничего не вернет , пока не будут доступны все результаты.
AsAsyncEnumerable()
будет «давать» каждый результат по мере его доступности. В примере OP они просто звонятToList()
, так что результат тот же. Однако, начиная с C# 8.0, вы также можете использовать «асинхронный поток», напримерawait foreach
, а затем воздействовать на каждую сущность по мере ее возврата. Например:
await foreach (var entity in DbContext.Set<Record>.Where(predicate).AsAsyncEnumerable())
{
// do something with entity...
}
Что касается того, что «лучше», это зависит от вашего варианта использования. Если вы просто возвращаете вызывающему абоненту несколько записей,ToListAsync()
все должно быть в порядке.
Однако предположим, что ваш запрос вернет 10000 записей. Вы, вероятно, не хотите хранить все это в памяти до того, как начнете с ними работать, потому что запрос может выполняться в течение многих секунд или даже минут и будет использовать много памяти.
В этом случае, вероятно, лучше использовать асинхронный поток. Это может быть ваш собственныйasync IAsyncEnumerable<T>
метод, которыйyield
свои собственные результаты. Затем вы можете связать их вместе, если это необходимо.
Фактически, начиная с ASP.NET Core 6 , вы можете вернутьIAsyncEnumerable<T>
непосредственно из вашего метода контроллера, и он будет "поставлять" эти результаты обратно вызывающей стороне.
Это делает намного более эффективным написание кода, который работает с большим количеством записей и/или возвращает их, потому что никогда не бывает точки, в которой они буферизуются в памяти.
Хотя существующий ответ pfx по-прежнему верен для.NET Core 2.x и ранее, AsAsyncEnumerable
официально добавлен в.NET Core 3.x. См. Комментарий Яна Кемпа для получения дополнительной информации.