Мне нужно реализовать асинхронное действие в моем контроллере для длительного вызова внешнего API.
Посмотрев несколько руководств, я реализовал свой метод следующим образом:
[AsyncTimeout(200)]
public async Task<ActionResult> DoAsync()
{
// Execute long running call.
return View();
}
У меня вопрос: достаточно ли этого, чтобы сделать действительно неблочную асинхронную? Нужно ли мне также применять оператор await, и если да, то как мне это сделать?
4 ответа
Мне нужно реализовать асинхронное действие в моем контроллере для длительного вызова внешнего API.
...
У меня вопрос: достаточно ли этого, чтобы сделать действительно неблочную асинхронную? Нужно ли мне также применять оператор await, и если да, то как мне это сделать?
Компилятор C #, вероятно, уже предлагает ключевое слово async
здесь избыточным:
[AsyncTimeout(200)]
public async Task<ActionResult> DoAsync()
{
// Execute long running call.
return View();
}
Тот факт, что вы добавили ключевое слово async
, не заставляет ваш метод волшебным образом работать в фоновом режиме.
Если вы сделаете что-то вроде await Task.Run(() => View())
, как предлагает другой ответ, вы все равно не выйдете за границы данный HTTP-запрос. Обработка запроса займет по крайней мере столько же времени, чтобы сгенерировать View
, так и без Task.Run
. Клиентский браузер по-прежнему будет его ждать.
Этот шаблон хорош для приложения пользовательского интерфейса, когда вам нужно выгрузить работу, связанную с процессором, в поток пула, чтобы избежать блокировки потока пользовательского интерфейса и сохранить отзывчивость пользовательского интерфейса. Однако использование его в обработчике HTTP-запросов внутри приложения ASP.NET почти никогда не является хорошей идеей. Это только повредит производительности и масштабируемости.
Одно из решений, обеспечивающее удобство использования, когда для составления View
требуется значительное количество времени, - это запустить фоновую задачу, которая охватывает границы одного HTTP-запроса . Затем используйте запросы AJAX, чтобы клиентский браузер всегда обновлялся. Вот отличный пример, который сделал Алан Д. Джексон:
Долгосрочные фоновые задачи в Asp.Net MVC3.
Однако выполнение длительной фоновой операции по нескольким HTTP-запросам внутри одного и того же серверного процесса ASP.NET не очень хорошая идея. Хотя реализовать этот подход относительно легко, он может создать проблемы с ремонтопригодностью, масштабируемостью и безопасностью IIS.
Возможно, вам будет лучше с отдельной Windows / Служба WCF для этого, которая будет предоставлять API на основе Task
. Затем используйте AJAX для периодического опроса службы WCF, используя специальный метод вашего контроллера ASP.NET MVC в качестве прокси для вызова опроса.
Как написал другой человек, вам нужно асинхронное действие, чтобы ожидать его, чтобы View()
асинхронно обернул его в Task.Run
[AsyncTimeout(200)]
public async Task<ActionResult> DoAsync()
{
// Execute long running call.
return await Task.Run(() => View());
}
Впоследствии этот метод в основном полезен для вызова из других асинхронных функций или обратных вызовов.
Чтобы написать неблокирующий асинхронный код, вам необходимо выполнить какую-то существующую неблокирующую асинхронную операцию, такую как Task.Delay()
, или асинхронный сетевой или файловый ввод-вывод.
Короче говоря, ключевое слово await
потребляет асинхронность; он его не создает.
Если у вас нет реальной асинхронной работы, await
не принесет вам никакой пользы.
View
как часть HTTP-запроса. Но браузер на стороне клиента может решить не ждать и тем временем прервать запрос.
У меня вопрос: достаточно ли этого, чтобы сделать действительно неблочную асинхронную? Нужно ли мне также применять оператор await, и если да, то как мне это сделать?
Вы должны использовать ключевое слово await
в асинхронных действиях MVC по следующим причинам:
- Если ваше действие изменяет состояние вашего приложения (обновляет базу данных и т. Д.), То ключевое слово
await
дает вам возможность откатить изменения в случае сбоя внешней службы. В противном случае это может привести к несогласованному состоянию, поскольку пользователь не может воспроизвести только данную асинхронную операцию, он может воспроизвести только все действие. - Среда размещения (IIS) может вызывать выгрузку домена приложения по различным причинам.. Когда это произойдет, ваше приложение никогда не сможет получить результат асинхронной операции. В случае обычной обработки запроса ASP.NET ожидает завершения каждой операции. Если выполнение некоторых запросов занимает слишком много времени (и превышает время ожидания завершения работы), ASP.NET прерывает их и отправляет ответ об ошибке.
Вот почему вы не должны использовать ни async
без await
, ни другие асинхронные методы .NET, такие как TPL. В этом случае предпочтительным решением является настраиваемая служба Windows с WCF, но она значительно усложняет задачи программирования, развертывания и обслуживания.
Конечно, вы можете использовать HostingEnvironment.RegisterObject
, вот хорошая статья. Но когда ASP.NET вызывает метод Stop
вашей реализации IRegisteredObject
интерфейс (во время выключения), у вас есть только 30 секунд (по умолчанию) для сохранения данных. Если у вас есть невыполненные асинхронные операции, вы должны прервать их, пометить их как неудачные и повторить их после перезапуска или отправить пользователям уведомления об ошибках. И если ваше хранилище также будет недоступно в это время, попрощайтесь со своими результатами (включая неудавшиеся результаты).
Вы также можете использовать постоянные очереди, надежную выборку и выделенных рабочих, которые прослушивают эти очереди внутри приложения ASP.NET. Это может защитить вас даже от завершения рабочего процесса. Более того, существует множество проектов, например Resque, Sidekiq, Pyres и т. д., но они предназначены для Другие языки.
Для .NET попробуйте HangFire - он еще находится в стадии разработки, но гораздо более стабильный, чем первоначальная реализация. таких систем и имеет множество различных функций.
Похожие вопросы
Связанные вопросы
Новые вопросы
c#
C# (произносится как «see Sharp») — это высокоуровневый мультипарадигменный язык программирования со статической типизацией, разработанный Microsoft. Код C# обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, которое включает в себя .NET, .NET Framework, .NET MAUI и Xamarin среди прочих. Используйте этот тег для ответов на вопросы о коде, написанном на C#, или о формальной спецификации C#.
return await Task.Run(() => View())
в ASP.NET не имеет смысла, это не приложение пользовательского интерфейса. Какова ваша причина этого? Ответ HTTP не будет отправлен клиенту, пока эта задача не будет завершена. Вы все еще используете поток для выполнения задачи. Итак, почему бы простоreturn View()
безasync
?