Предположим, нам нужно записать в базу данных список из 1000 элементов через асинхронный поток. Лучше ли ждать 1000 раз асинхронного оператора вставки или обернуть все 1000 вставок в одном синхронном методе, заключенном в оператор Task.Run
, в ожидании одного раза?Многие ждут для метода Async или одного ожидания для упаковки Task.Run?
Например, SqlCommand
имеет каждый метод в сочетании с его версией async
. В этом случае у нас есть оператор insert, поэтому мы можем позвонить ExecuteNonQuery
или ExecuteNonQueryAsync
.
Часто в инструкциях async/wait мы читаем, что если у вас есть асинхронная версия, доступная для какого-либо метода, вы должны ее использовать. Предположим, что мы пишем:
async Task Save(IEnumerable<Savable> savables)
{
foreach(var savable in savables)
{
//create SqlCommand somehow
var sqlCmd = CreateSqlCommand(savable);
//use asynchronous version
await sqlCmd.ExecuteNonQueryAsync();
}
}
Этот код очень прост. Тем не менее, каждый раз, когда он выходит из части ожидания, он также возвращается в поток пользовательского интерфейса, а затем обратно в фоновый поток в следующем ожидании и т. Д. (Не так ли?). Это означает, что пользователь может увидеть некоторое отставание, поскольку поток пользовательского интерфейса непрерывно прерывается продолжением await
для выполнения следующего цикла foreach
, и за это время пользовательский интерфейс немного замерзает.
Я хочу знать, если я лучше писать код так:
async Task Save(IEnumerable<Savable> savables)
{
await Task.Run(() =>
{
foreach(var savable in savables)
{
//create SqlCommand somehow
var sqlCmd = CreateSqlCommand(savable);
//use synchronous version
sqlCmd.ExecuteNonQuery();
}
});
}
Таким образом, вся foreach
выполняется на вторичном потоке, без непрерывного переключения между нитью UI и второстепенному. Это подразумевает, что поток пользовательского интерфейса может обновлять View в течение всего времени foreach
(например, счетчик или индикатор выполнения), то есть пользовательский лаг не воспринимается.
Я прав? или мне что-то не хватает о «асинхронном обратном пути»?
Я не ищу простые ответы на основе мнений. Я ищу объяснение инструкций async/await в случае, если это и для наилучшего способа его решения.
EDIT:
Я прочитал this question, но это не то же самое. Это вопрос о выборе SINGLE await
по асинхронному методу в сравнении с одним Task.Run
. Этот вопрос связан с последствиями вызова 1000 await
и накладными расходами ресурсов из-за непрерывного переключения между потоками.
Возможный дубликат [Вызов метода асинхронизации с использованием Task.Run кажется неправильным?] (Http://stackoverflow.com/questions/32606485/calling-an-async-method-using-a-task-run-seems -wrong) – Liam
Что вам не хватает, так это то, что Threads чрезвычайно дороги, поэтому вы действительно хотите избежать их создания, если сможете. – Aron
Метод 'Task.Run' - это * синхронизация по асинхронному шаблону *. Не делайте этого – Liam