Любой недостаток использования ExecuteReaderAsync из C# AsyncCTP
-
12-11-2019 - |
Вопрос
Есть несколько статей, в которых указывается, что асинхронные вызовы базы данных — плохая идея в .NET.
- Должны ли мои вызовы базы данных быть асинхронными?
- Должны ли мои вызовы базы данных быть асинхронными? Часть II
В C# Async CTP есть System.Data.SqlClient.SqlCommand
расширение называется ExecuteReaderAsync
.У меня есть некоторые операции, как показано ниже, в моем существующем коде:
var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["hubConnectionString"].ConnectionString;
using (var conn = new SqlConnection(connectionString)) {
using (var cmd = new SqlCommand()) {
cmd.Connection = conn;
cmd.CommandText = "sp$DetailsTagsGetAllFromApprovedPropsWithCount";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
conn.Open();
var reader = cmd.ExecuteReader();
while (reader.Read()) {
//do the reading
}
conn.Close();
}
}
В моем коде есть несколько подобных операций.Итак, у меня есть мысли о преобразовании их в асинхронные.
Но с другой стороны, я не вижу особой привлекательности в этом подходе (может быть, я не в том направлении смотрю, кто знает!).
Итак, есть ли какие-либо недостатки в использовании этой новой модели асинхронного программирования?
Редактировать:
Предполагая, что я реорганизую код, как показано ниже:
public async Task<IEnumerable<Foo>> GetDataAsync() {
List<Foo> foos = new List<Foo>();
var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["hubConnectionString"].ConnectionString;
using (var conn = new SqlConnection(connectionString)) {
using (var cmd = new SqlCommand()) {
cmd.Connection = conn;
cmd.CommandText = "sp$DetailsTagsGetAllFromApprovedPropsWithCount";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
conn.Open();
var reader = await cmd.ExecuteReaderAsync();
while (reader.Read()) {
//do the reading
//create foos
}
conn.Close();
}
}
return foos;
}
Насколько я понял из ключевого слова await, оно преобразует код, который стоит после него, в продолжение.Кроме того, когда он нажимает ключевое слово await, он немедленно возвращается к вызывающей стороне независимо от статуса операции.По завершении он возвращается и запускает код продолжения.
Вот что я имею в виду.
Решение
В этом я не согласен с Рикой.Команды Async DB не только хороши, они имеют решающее значение для достижения масштабируемости и пропускной способности. и задержка.Его возражение по поводу времени нарастания пула потоков применимо только к веб-серверу с низкими объемами трафика.
В ситуации с высоким трафиком (и это единственное, что имеет значение) пулу потоков не придется ждать «внедрения» новых потоков.Асинхронное выполнение команд SQL важно не только с точки зрения работоспособности запросов/потоков веб-сервера, но также с точки зрения общего времени жизни/задержки запроса:некоррелированные вызовы БД могут выполняться параллельно, а не последовательно.Одно только это обычно приводит к значительному уменьшению задержки HTTP-запроса, которую ощущает пользователь.Другими словами, ваши страницы загружаются быстрее.
Однако небольшой совет:Команда SQL не является по-настоящему асинхронной, пока вы не включите Asynchronous Processing=true
в строке подключения.Хотя это не установлено (и по умолчанию не установлено, Редактировать:начиная с .NET Framework < 4.5. Asynchronous Processing
больше не требуется) ваши «асинхронные» вызовы BeginExecuteReader
являются не чем иным, как притворством, вызов запустит поток и заблокирует что нить.Когда включена настоящая асинхронная обработка в строке подключения тогда вызов действительно асинхронный, а обратный вызов основан на завершении ввода-вывода.
Предупреждение:асинхронная команда SQL завершается, как только первый результат возвращается клиенту, и информационные сообщения считаются результатом.
create procedure usp_DetailsTagsGetAllFromApprovedPropsWithCount
as
begin
print 'Hello';
select complex query;
end
Вы потеряли все преимущества асинхронности.А print
создает результат, который отправляется обратно клиенту, который завершает асинхронную команду, и выполнение на клиенте возобновляется и продолжается с помощью «reader.Read()».Сейчас что будет блокироваться до тех пор, пока сложный запрос не начнет давать результаты.Ты спрашиваешь 'кто ставит print
в процедуре? но print
может быть замаскирован во что-то другое, возможно, в нечто столь же невинное, как INSERT
который выполняет без сначала выпустив SET NOCOUNT ON
.
Другие советы
Я заметил, что на следующий вопрос не ответили:
Итак, есть ли какие-либо недостатки в использовании этой новой модели асинхронного программирования?
А недостаток который очень минимальный (меньший процессор/меньшая память), потому что существует вероятность запуска любого кода после оператора await. может выполняется в отдельном потоке, существует конечный автомат для хранения состояния текущего потока, чтобы продолжение работы можно было обрабатывать в другом потоке.Вы можете прочитать больше о Конечный автомат await/async в блоге Dixin - Понимание C# async/await (1) Компиляция.