Это потому, что вы неправильно используете async/await
.Обратите внимание, что у вас есть 2 задачи: одна возвращается Task.Run
, а другая - AsyncMethod
.Зацикливаясь на верхнем уровне Task
, вы блокируете поток запроса и продолжение Task.Run
, которое
hub.Clients.All.message($"<br>==M2== Finish inner method...");
, не может быть выполнено в ASP.NET, поскольку оно использует контекст синхронизации, который в случае, если ASP.NET обеспечивает выполнение не более одного потока за раз для потоков, которые совместно используют контекст синхронизации (поток запросов и потоки продолжения совместно используют контекст).Таким образом, второе задание также не может быть завершено.Консоль не использует контекст синхронизации, поэтому ваши продолжения запланированы в пуле потоков.Вам нужно либо использовать ConfigureAwait(flase)
для планирования ваших асинхронных задач, либо делать все асинхронно (что более правильно).Вы можете увидеть пример здесь о том, как реализовать прогресс для async
задач.
Обновление : для придания некоторой ясности цели контекста синхронизации.Давайте представим, что типичная лебедка асинхронного потока запускается асинхронным событием (пользовательский ввод, входящий запрос и т. Д.) И завершается некоторым асинхронным действием (передача данных во внешний источник данных, файл, извлечение данных из веб-ресурса и т. Д.),Асинхронное приложение имеет дело со многими из таких потоков, которые из-за их асинхронной природы могут запускаться одновременно и могут завершаться одновременно, и этот факт среди преимуществ налагает некоторые подводные камни.Например, если поток вызывает несколько асинхронных операций, параллелизм их продолжений может быть проблемой.Решением является синхронизация продолжений - вот где контекст синхронизации вступает в игру.Таким образом, в целом он представляет собой некоторую абстракцию для планирования упорядоченного выполнения с помощью двух методов «Отправить» и «Пост», которые имеют семантику «вызвать и ждать» и «запустить и забыть» соответственно.Почему не просто примитивы синхронизации?Вкратце контекст синхронизации обеспечивает более общий подход в виде паттерна полусинхронизация / полусинхронизация.Часто ресурсы, используемые для обслуживания асинхронных продолжений, довольно дороги (например, в ОС семейства Windows механизм портов завершения ввода-вывода подразумевает использование специального пула потоков для обслуживания завершенных запросов ввода-вывода), и настоятельно рекомендуется не занимать такие ресурсы дольше, чемнеобходимый период времени, поэтому подход «запустить и забыть» часто является предпочтительным способом вместо ожидания объекта синхронизации и блокировки потока, который будет обслуживать другие асинхронные продолжения, а контекст синхронизации обеспечивает абстракцию, которая позволяет эффективно использовать базовую инфраструктуру.В качестве побочного эффекта некоторых реализаций контекста синхронизации можно выделить возможность делегировать выполнение некоторого кода из одного потока в другой конкретный поток (как это делают контексты синхронизации WinForms или WPF), но я бы сказал, что это скорее зависит от реализации.