Все еще запутался в ConfigureAwait (false), используемом с GetAwaiter и GetResult в C #.Получение тупика или метод, не возвращающийся - PullRequest
0 голосов
/ 25 января 2019

Я прочитал: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html и принятый ответ в взаимоблокировке даже после использования ConfigureAwait (false) в потоке Asp.Net , но я слишком плотный, чтобы видеть, что происходит.

У меня есть код:

private void CancelCalibration()
{
    // ...
    TaskResult closeDoorResult =  CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult(); 
    CalibrationState = CalibrationState.Idle;

    return;
    // ...                   
}

private async Task<TaskResult> CloseLoadDoor()
{       
    TaskResult result = await _model.CloseLoadDoor().ConfigureAwait(false);           
    return result;
}
public async Task<TaskResult> CloseLoadDoor()
    {
        TaskResult result = new TaskResult()
        {
            Explanation = "",
            Success = true
        };
        await _robotController.CloseLoadDoors().ConfigureAwait(false);
        return result;
    }
    public async Task CloseLoadDoors()
    {                         
            await Task.Run(() => _robot.CloseLoadDoors());              
    }

     public void CloseLoadDoors()
    {
   // syncronous code from here down              
   _doorController.CloseLoadDoors(_operationsManager.GetLoadDoorCalibration());                
        }

Как видите, CloseLoadDoor объявлен асинхронным.Я подумал (особенно из первой статьи выше), что если я использую ConfigureAwait (false), я могу вызвать асинхронный метод без тупика.Но это то, что я, кажется, получаю.Вызов «CloseLoadDoor (). ConfigureAwait (false) .GetAwaiter (). GetResult () никогда не возвращается!

Я использую GetAwaiter.GetResult, потому что CancelCalibration НЕ является асинхронным методом. Это определенный обработчик кнопкичерез шаблон MVVM:

public ICommand CancelCalibrationCommand
        => _cancelCalibrationCommand ?? (_cancelCalibrationCommand = new DelegateCommand(CancelCalibration));

Если кто-то скажет мне, что я могу сделать асинхронную отмену калибровки, пожалуйста, скажите мне, как. Могу ли я просто добавить async в объявление метода? ОДНАКО я быЯ все еще хотел бы знать, почему шаблон ConfigureAwait.GetAwaiter.GetResult доставляет мне неприятности. Насколько я понимаю, GetAwaiter.GetResult был способом вызова асинхронного метода из синхронных методов, когда изменение сигнатуры не вариант.

Япредполагаю, что я на самом деле не освобождаюсь от использования оригинального контекста, но что я делаю не так и каков порядок, чтобы это исправить? Спасибо, Дейв

1 Ответ

0 голосов
/ 26 января 2019

Я подумал (особенно из первой статьи выше), что, если я использую ConfigureAwait (false), я мог бы вызвать асинхронный метод без тупика.

В этой статье есть важное примечание:

Использование ConfigureAwait (false) для избежания взаимоблокировок - опасная практика. Вы должны будете использовать ConfigureAwait (false) для каждого ожидания при переходном закрытии всех методов, вызываемых кодом блокировки, , включая все сторонние и сторонние коды . Использование ConfigureAwait (false) для избежания взаимоблокировки в лучшем случае просто взлом).

Итак, ConfigureAwait(false) используется для каждые await в переходном замыкании? Это значит:

  • Использует ли CloseLoadDoor ConfigureAwait(false) для каждого await? По опубликованному коду видно, что он делает.
  • Использует ли _model.CloseLoadDoor ConfigureAwait(false) для каждого await? То, что мы не можем видеть.
  • Использует ли каждый метод, вызываемый _model.CloseLoadDoor, ConfigureAwait(false) для каждого await?
  • Использует ли каждый метод, вызываемый каждым методом, вызываемым _model.CloseLoadDoor, ConfigureAwait(false) для каждого await?
  • и т.д.

Это, по крайней мере, тяжелое техническое обслуживание. Я подозреваю, что где-то в стеке вызовов отсутствует ConfigureAwait(false).

Как следует из этой записки:

Как видно из заголовка этого поста, лучшим решением будет «Не блокировать асинхронный код».

Другими словами, весь смысл этой статьи - «Не блокировать асинхронный код». Это не говорит: «Блокируйте асинхронный код с помощью этого аккуратного трюка».

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

<Ч />

В примечании, в коде CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult(), ConfigureAwait ничего не делает. Это «настроить ожидание», а не «настроить задачу». Поскольку там нет await, ConfigureAwait(false) не имеет никакого эффекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...