Реализация преимуществ асинхронного / ожидающего в веб-API, когда синхронный метод находится в смеси - PullRequest
2 голосов
/ 08 октября 2019

Моя цель - повысить масштабируемость веб-API, над которым я работаю. Для этого я реализовал действия контроллера для async. Идея состоит в том, что потоки запросов освобождаются и доступны для обработки других входящих запросов. Однако победивший ответ из Effectively use async/await with ASP.NET Web API гласит:

Вам потребуется действительно асинхронная реализация, чтобы получить преимущества масштабируемости async.

В конечном итоге мой код должен вызывать метод из сторонней библиотеки, который является очень синхронным, однопоточным и связан с вводом / выводом. Так что на самом деле единственный способ сделать это - через Task.Run(), который, как я предполагаю, сохранит поток - тем самым отменив преимущества async / await.

Так есть ли способ реализовать преимущества async / await в сценарии Web API, когда в миксе есть синхронная операция?

Ответы [ 2 ]

4 голосов
/ 08 октября 2019

Так есть ли способ реализовать преимущества async / await в сценарии Web API, когда в миксе есть синхронная операция?

Нет. Причина проста: асинхронность дает свои преимущества, освобождая поток, а синхронная операция блокирует поток.

Преимущество асинхронности на стороне сервера - масштабируемость . Асинхронность обеспечивает лучшую масштабируемость, потому что она освобождает свой поток, когда он не нужен .

По определению синхронный API блокирует поток. Если API является операцией, связанной с вводом / выводом, то он блокирует поток, который в основном просто ожидает ввода / вывода, т. Е. Поток не нужен, но также не может быть освобожден.

Там нет никакого способа обойти это;синхронный API должен блокировать поток, поэтому вы не сможете получить преимущества асинхронности.

Если у вас было приложение с графическим интерфейсом, то существует обходной путь. На стороне клиента основным преимуществом асинхронности является отзывчивость . Асинхронность обеспечивает лучшую скорость отклика, освобождая поток пользовательского интерфейса, когда он не нужен.

Для приложений с графическим интерфейсом вы можете использовать Task.Run для блокировки потока пула потоков, и ваш поток пользовательского интерфейса остается отзывчивым;это подходящий обходной путь. В серверных приложениях использование Task.Run, подобного этому, является антипаттерном, так как он вызывает переключение потоков, а затем вы все равно получаете заблокированный поток (предотвращая любые преимущества масштабируемости), поэтому Task.Run просто замедляет ваш код без какой-либо выгоды. вообще.

1 голос
/ 08 октября 2019

Все зависит от того, какой другой код задействован. Если во время выполнения операций ввода-вывода может выполняться много другого кода, то да, Task.Run () был бы идеальным, просто убедитесь, что ожидаете задачу там, где это необходимо.

Если естьэто не код, который мог бы выполняться во время операций ввода / вывода, тогда Task.Run () не является хорошим планом, поскольку вы блокируете основной поток и добавляете новый поток в любом случае, приводя к худшему масштабированию, чем просто оставляя его синхронным.

В конечном итоге, если вы используете стороннюю синхронную библиотеку и хотите оптимизировать масштабирование своего веб-API с помощью асинхронных вызовов, вам следует попытаться воссоздать библиотеку самостоятельно с помощью асинхронных вызовов ввода-вывода. Не стесняйтесь проверить https://docs.microsoft.com/en-us/dotnet/standard/io/asynchronous-file-i-o для получения дополнительной информации.

...