Почему происходят асинхронные взаимоблокировки C #? [Дубликат]

Функции mysql_:

  1. устарели - они больше не поддерживаются
  2. не позволяют легко перемещаться в другой бэкэнд базы данных
  3. не поддерживают подготовленные инструкции, поэтому
  4. поощряет программистов использовать конкатенацию для создания запросов, что приводит к уязвимости SQL-инъекций
70
задан 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 24 August 2018 в 17:05
поделиться

Я просто возился с этой проблемой снова в проекте 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);
    }
2
ответ дан Herre Kuijpers 24 August 2018 в 17:05
поделиться

Еще один важный момент заключается в том, что вы не должны блокировать задачи и использовать 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 24 August 2018 в 17:05
поделиться
  • Факт 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().

7
ответ дан Phillip Ngan 24 August 2018 в 17:05
поделиться
Другие вопросы по тегам:

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