Асинхронный вызов замораживает приложение C #, используемое синхронно [дубликат]

Вы также можете применить положение: абсолютное к родительскому Div. Полный код ниже

  & lt; html & gt;  & Л; тело & GT;  & lt; div style = "padding-left: 50px;" & gt;  & lt; div style = "height: 100px" & gt;  Некоторое содержимое & lt; div & gt;  & lt; div style = "height: 80px; position: absolute; padding-left: 20px;" & gt;  & lt; div id = "absPos" style = "padding: 10px; position: absolute; left: 0px; top: 0px; background-color: red;" & gt; & lt; / div & gt;  Некоторый текст & lt; / div & gt;  & Lt; / дел & GT;  & Lt; / тело & GT;  & Lt; / HTML & GT;   
68
задан Gennady Vanin Геннадий Ванин 30 April 2013 в 12:57
поделиться

4 ответа

Посмотрите пример в здесь , у Стивена есть ясный ответ для вас:

Так вот что происходит, начиная с метода верхнего уровня (Button1_Click for UI / MyController.Get для ASP.NET):

  1. Метод верхнего уровня вызывает GetJsonAsync (в контексте UI / ASP.NET).
  2. GetJsonAsync запускает REST запрос, вызвав HttpClient.GetStringAsync (все еще в контексте).
  3. GetStringAsync возвращает незавершенную задачу, указывая, что запрос REST не завершен.
  4. GetJsonAsync ожидает задачу, возвращенную GetStringAsync. Контекст захвачен и будет использоваться для продолжения использования метода GetJsonAsync позже. GetJsonAsync возвращает незавершенную задачу, указывая, что метод GetJsonAsync не завершен.
  5. Метод верхнего уровня синхронно блокирует задачу, возвращенную GetJsonAsync. Это блокирует контекстный поток.
  6. ... В конце концов, запрос REST завершится. Это завершает задачу, которая была возвращена GetStringAsync.
  7. Продолжение для GetJsonAsync теперь готово к запуску и ожидает, что контекст будет доступен, чтобы он мог выполняться в контексте.
  8. Тупик. Метод верхнего уровня блокирует поток контекста, ожидая завершения GetJsonAsync, и GetJsonAsync ожидает, что контекст будет бесплатным, чтобы он мог завершить. Для примера пользовательского интерфейса «контекст» представляет собой контекст пользовательского интерфейса; для примера ASP.NET «контекст» представляет собой контекст запроса ASP.NET.
  9. Еще одна ссылка, которую вы должны прочитать:

    Ожидание и пользовательский интерфейс, тупики! О, мой!

64
ответ дан svick 16 August 2018 в 01:30
поделиться

Я просто возился с этой проблемой снова в проекте MVC.Net. Если вы хотите вызывать методы async из PartialView, вам не разрешается выполнять асинхронную процедуру PartialView. Вы получите исключение, если вы это сделаете.

Итак, в основном простой способ обхода в сценарий, в котором вы хотите вызвать метод async из метода синхронизации, вы можете сделать следующее:

  1. перед вызовом, очистите SynchronizationContext
  2. , выполните здесь тупик, подождите, пока он закончит
  3. восстановить SynchronizationContext

Пример:

    public ActionResult DisplayUserInfo(string userName)
    {
        // trick to prevent deadlocks of calling async method 
        // and waiting for on a sync UI thread.
        var syncContext = SynchronizationContext.Current;
        SynchronizationContext.SetSynchronizationContext(null);

        //  this is the async call, wait for the result (!)
        var model = _asyncService.GetUserInfo(Username).Result;

        // restore the context
        SynchronizationContext.SetSynchronizationContext(syncContext);

        return PartialView("_UserInfo", model);
    }
1
ответ дан Herre Kuijpers 16 August 2018 в 01:30
поделиться

Еще один важный момент заключается в том, что вы не должны блокировать задачи и использовать async до конца, чтобы предотвратить взаимоблокировки. Тогда это будет асинхронная, а не синхронная блокировка.

public async Task<ActionResult> ActionAsync()
{

    var data = await GetDataAsync();

    return View(data);
}

private async Task<string> GetDataAsync()
{
    // a very simple async method
    var result = await MyWebService.GetDataAsync();
    return result.ToString();
}
4
ответ дан marvelTracker 16 August 2018 в 01:30
поделиться
  • 1
    Что делать, если я хочу, чтобы основной (UI) поток блокировался до завершения задачи? Или, например, в приложении консоли? Предположим, я хочу использовать HttpClient, который только поддерживает async ... Как использовать его синхронно без риска тупика ? Этот должен быть возможен. Если WebClient можно использовать таким образом (из-за наличия методов синхронизации) и работает отлично, то почему это не может быть сделано с HttpClient? – Dexter 6 February 2017 в 16:35
  • 2
    См. Ответ от Филиппа Нгана выше (я знаю, что это было опубликовано после этого комментария): Очередь в ожидании другого потока, который не заблокирован, например. использовать var data = Task.Run (GetDataAsync). Результат – Jeroen 22 December 2017 в 20:58
  • 3
    @Dexter - re & quot; Что делать, если я хочу, чтобы основной (UI) поток блокировался до завершения задачи? & quot; - действительно ли вы хотите заблокировать поток пользовательского интерфейса, то есть пользователь ничего не может сделать, даже не может отменить - или вы не хотите продолжать использовать метод, в котором находитесь? & Quot; Await & Quot; или "Task.ContinueWith" обработайте последний случай. – ToolmakerSteve 27 June 2018 в 19:41
  • Факт 1: GetDataAsync().Result; будет выполняться, когда задача, возвращаемая GetDataAsync(), завершается, тем временем она блокирует поток пользовательского интерфейса
  • Факт 2: продолжение ожидания (return result.ToString() ]) помещается в очередь потока UI для выполнения
  • Факт 3: Задача, возвращаемая GetDataAsync(), будет завершена, когда будет запущено его очередное продолжение
  • Факт 4: Очередное продолжение никогда (факт 1)

Тупик!

Тупик может быть нарушен предоставленными альтернативами, чтобы избежать Факт 1 или Факт 2.

  • Избегайте 1,4. Вместо блокировки потока пользовательского интерфейса используйте var data = await GetDataAsync(), который позволяет потоку пользовательского интерфейса продолжать работать
  • Избегать 2,3. Очередь продолжит ожидание другого потока, который не блокируется, например. используйте var data = Task.Run(GetDataAsync).Result, который выведет продолжение в контекст синхронизации потока threadpool. Это позволяет завершить задачу GetDataAsync().

Это очень хорошо объясняется в статье Стивена Тууба , примерно наполовину вниз, где он использует пример DelayAsync().

6
ответ дан Phillip Ngan 16 August 2018 в 01:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: