簡體   English   中英

仍然對與C#中的GetAwaiter和GetResult一起使用的ConfigureAwait(false)感到困惑。 使死鎖或方法不返回

[英]Still confused on ConfigureAwait(false) used with GetAwaiter and GetResult in C#. Getting a deadlock or method not returning

我已經讀過: http : //blog.stephencleary.com/2012/07/dont-block-on-async-code.html死鎖的公認答案, 即使在Asp.Net流中使用ConfigureAwait(false)之后,也只是太稠密,看不到發生了什么事。

我有代碼:

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));

如果有人要告訴我可以使CancelCalibration異步,請告訴我如何。 我可以將async添加到方法聲明中嗎? 但是,我仍然想知道為什么ConfigureAwait.GetAwaiter.GetResult模式給我帶來麻煩。 我的理解是,當不能選擇更改簽名時, GetAwaiter.GetResult是一種從同步方法中調用異步方法的方法。

我猜我並沒有真正從使用原始上下文中解放出來,但是我在做錯什么,以及解決該問題的模式是什么? 謝謝戴夫

我以為(特別是從以上第一篇文章中)我可以通過使用ConfigureAwait(false)來調用一個沒有死鎖的異步方法。

那篇文章有一個重要的說明:

使用ConfigureAwait(false)避免死鎖是一種危險的做法。 在阻塞代碼調用的所有方法( 包括所有第三方代碼和第二方代碼 )的傳遞關閉中,您必須為每次等待使用ConfigureAwait(false)。 使用ConfigureAwait(false)避免死鎖充其量只是一種破解)。

那么,是否在傳遞閉包中為每個 await使用ConfigureAwait(false) 這意味着:

  • CloseLoadDoor是否每次await都使用ConfigureAwait(false) 從發布的代碼中我們可以看到它確實如此。
  • _model.CloseLoadDoor是否每次await都使用ConfigureAwait(false) 我們看不到。
  • _model.CloseLoadDoor調用的每個方法是否都為每次await使用ConfigureAwait(false)
  • _model.CloseLoadDoor調用的每個方法調用的每個方法是否都對每次await使用ConfigureAwait(false)
  • 等等

至少這是一個沉重的維護負擔。 我懷疑在調用堆棧的某個地方,缺少一個ConfigureAwait(false)

該注釋總結如下:

正如該帖子的標題所指出的那樣,更好的解決方案是“不要阻止異步代碼”。

換句話說,該文章的重點是“不要阻止異步代碼”。 這並不是說“使用這一巧妙技巧阻止異步代碼”。

如果您確實想擁有一個同時支持同步和異步調用者的API,建議在我關於brownfield async的文章中使用bool參數hack。


附帶說明一下,在代碼CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult()ConfigureAwait不會執行任何操作。 它是“等待配置”,而不是“配置任務”。 由於那里沒有await ,因此ConfigureAwait(false)無效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM