У меня есть метод в приложении ASP.NET, который требует довольно много времени для завершения. Вызов этого метода может возникать до 3 раз в течение одного пользовательского запроса в зависимости от состояния кэша и параметров, которые пользователь предоставляет. Каждый вызов занимает около 1-2 секунд. Сам метод является синхронным вызовом службы, и нет возможности переопределить реализацию.
Так синхронный вызов службы выглядит примерно следующим:Обертка синхронного кода в асинхронный вызов
public OutputModel Calculate(InputModel input)
{
// do some stuff
return Service.LongRunningCall(input);
}
И использование метода (обратите внимание, что вызов метода может произойти более чем один раз):
private void MakeRequest()
{
// a lot of other stuff: preparing requests, sending/processing other requests, etc.
var myOutput = Calculate(myInput);
// stuff again
}
Я попытался изменить реализацию с моей стороны, чтобы обеспечить одновременную работу этого метода, и вот что я до сих пор сделал.
public async Task<OutputModel> CalculateAsync(InputModel input)
{
return await Task.Run(() =>
{
return Calculate(input);
});
}
Использование (часть «делать другие вещи» код работает одновременно с вызовом службы):
private async Task MakeRequest()
{
// do some stuff
var task = CalculateAsync(myInput);
// do other stuff
var myOutput = await task;
// some more stuff
}
Мой вопрос заключается в следующем. Я использую правильный подход, чтобы ускорить выполнение в приложении ASP.NET, или я делаю ненужную работу, пытаясь запустить синхронный код асинхронно? Может ли кто-нибудь объяснить, почему второй подход не является вариантом в ASP.NET (если это действительно не так)? Кроме того, если такой подход применим, мне нужно вызвать такой метод асинхронно, если он является единственным вызовом, который мы могли бы выполнить в данный момент (у меня есть такой случай, когда в ожидании завершения не нужно ничего другого)?
Большинство статей в сети по этой теме охватывает подход async-await
с кодом, который уже предоставляет методы awaitable
, но это не мое дело. Here - хорошая статья, описывающая мой случай, который не описывает ситуацию с параллельными вызовами, отклоняя опцию обертывания вызова синхронизации, но, на мой взгляд, моя ситуация - это именно то, что нужно сделать.
Заранее благодарим за помощь и советы.
Большое спасибо за подробный ответ. Еще одна вещь, которую я хочу уточнить. Когда я запускаю выполнение с помощью 'Task.Run', содержимое запускается в другом потоке, который берется из пула потоков. Тогда нет необходимости вообще блокировать блокирующие вызовы (такие как мой вызов для обслуживания) в 'Run', потому что они всегда будут потреблять по одному потоку каждый, который будет заблокирован во время выполнения метода. В такой ситуации единственное преимущество, которое осталось от «асинхронного ожидания» в моем случае, - это выполнение нескольких действий за раз. Пожалуйста, исправьте меня, если я ошибаюсь. – Eadel
Также, чтобы указать, что «услуга» - это вызов удаленного веб-сервиса, который не связан с ЦП с нашим сервером, но для получения ответа от удаленной машины требуется некоторое время. Что касается второго предположения, мы предоставляем пользователю возможность выполнять некоторую работу во время большинства запросов, но в нашем случае важна скорость и загрузка сервера. Приложение не является внутренним, поэтому существует возможность большого количества запросов с максимальной нагрузкой. – Eadel
Да, единственное преимущество, которое вы получаете от 'Run' (или' Parallel'), - это параллелизм. Операции по-прежнему блокируют поток.Поскольку вы говорите, что услуга является веб-службой, я не рекомендую использовать 'Run' или' Parallel'; вместо этого напишите асинхронный API для этой службы. –