Можно ли использовать Async при использовании ForEach? Ниже приведен код, который я пытаюсь выполнить:
using (DataContext db = new DataLayer.DataContext())
{
db.Groups.ToList().ForEach(i => async {
await GetAdminsFromGroup(i.Gid);
});
}
Я получаю сообщение об ошибке:
Имя Async не существует в текущем контексте.
Метод, в который заключен оператор using, имеет значение async.
c#
async-await
Джеймс Джеффри
источник
источник
List.ForEach()
не является частью LINQ.async
. Они мне очень помогли!foreach
сawait
вашим телом цикла.ForEach
принимает только синхронный тип делегата, и нет перегрузки, принимающей асинхронный тип делегата. Итак, краткий ответ: «никто не писал асинхронныйForEach
». Более длинный ответ заключается в том, что вам придется предположить некоторую семантику; например, должны ли элементы обрабатываться по одному (напримерforeach
) или одновременно (напримерSelect
)? Разве асинхронные потоки по одному - не лучшее решение? Если одновременно, должны ли результаты быть в исходном порядке элементов или в порядке завершения? Должен ли он выйти из строя при первом сбое или дождаться завершения всех? И т.д.SemaphoreSlim
для ограничения асинхронных задач.Этот небольшой метод расширения должен дать вам безопасную в отношении исключений асинхронную итерацию:
Поскольку мы меняем тип возвращаемого значения лямбды с
void
наTask
, исключения будут распространяться правильно. Это позволит вам на практике написать что-то вроде этого:источник
async
должно быть раньшеi =>
ForEachAsync
сути, это библиотечный метод, поэтому ожидание, вероятно, следует настроить с помощьюConfigureAwait(false)
.Простой ответ - использовать
foreach
ключевое слово вместоForEach()
методаList()
.источник
Вот актуальная рабочая версия вышеупомянутых вариантов async foreach с последовательной обработкой:
Вот реализация:
В чем ключевое отличие?
.ConfigureAwait(false);
который сохраняет контекст основного потока при асинхронной последовательной обработке каждой задачи.источник
Начиная с
C# 8.0
, вы можете создавать и использовать потоки асинхронно.Больше
источник
MoveNext
перечислителя. Это важно в случаях, когда перечислитель не может мгновенно получить следующий элемент и должен ждать, пока один из них станет доступным.Добавьте этот метод расширения
А затем используйте так:
источник
Проблема заключалась в том, что
async
ключевое слово должно стоять перед лямбда, а не перед телом:источник
async void
. У этого подхода есть проблемы с обработкой исключений и знанием того, когда завершаются асинхронные операции.