[英]How can I call an async method within a sync method?
我正在嘗試在同步方法(SignIn)中調用異步任務(SIn)。 我需要synch方法,因為我將ref傳遞給該方法。 但是,當我調用異步任務時,GUI被凍結。 異步任務是使用onedrive sdk的簡單登錄。
我試圖等待任務,但GUI仍然凍結。 我也嘗試過創建新的線程,但是它也沒有用。 如何調用異步方法?
public override bool SignIn(ref User user)
{
try
{
signInEnd = false;
signinUser = user;
Task<bool> task = SIn();
task.Wait();
return task.Result;
}
catch(Exception e)
{
return false;
}
}
public async Task<bool> SIn()
{
var msaAuthProvider = new MsaAuthenticationProvider(
this.oneDriveClientId,
this.oneDriveReturnUrl,
this.scopes,
new CredentialVault(this.oneDriveClientId));
await msaAuthProvider.AuthenticateUserAsync();
driveClient = new OneDriveClient(this.oneDriveBaseUrl, msaAuthProvider);
}
調用Wait()
阻止UI線程,這意味着SIn()
的繼續SIn()
即AuthenticateUserAsync()
返回的Task
完成后最終將要執行的部分AuthenticateUserAsync()
將無法在此線程上執行。 這將導致死鎖。
您可以通過在SIn()
調用ConfigureAwait(false)
來避免捕獲上下文,從而解決此問題:
public async Task<bool> SIn()
{
var msaAuthProvider = new MsaAuthenticationProvider(
this.oneDriveClientId,
this.oneDriveReturnUrl,
this.scopes,
new CredentialVault(this.oneDriveClientId));
await msaAuthProvider.AuthenticateUserAsync().ConfigureAwait(false);
driveClient = new OneDriveClient(this.oneDriveBaseUrl, msaAuthProvider);
}
但是,針對此類問題的“真正”解決方案不是混合使用異步代碼和同步代碼,即SignIn
應該是異步的並等待SIn()
。 不要通過調用Wait()
或Result
阻塞異步代碼:
public Task<bool> SignIn(User user)
{
try
{
...
return await SIn();
}
catch (Exception e)
{
return false;
}
}
請參閱@Stephen Cleary的博客文章 ,以獲取有關此信息的更多信息。
mm8是對的,不要從sync方法內部調用async是解決問題的最佳方法,
請記住, public async void EventHandler()
方法是專門為從gui鏈接控件中運行長時間運行的任務而設計的
但是,當僅需要更改一小部分時,並非總是可能將整個系統重寫為異步的
在這種情況下,您應該避免等待結果,因為這會使異步過程變得毫無意義,但是您可以做的是將同步代碼分為前后兩部分
即
public async Task<string> GetData(int delay)
{
await Task.Delay(delay);
return "complete";
}
public void StartGettingData()
{
GetData(5000).ContinueWith(t => CompleteGetData(t.Result), TaskScheduler.Current);
}
public void CompleteGetData(string message)
{
UpdateStatus(message);
}
此方法的確增加了復雜性,要求您自己確保線程安全,這就是引入異步/等待功能的原因
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.