[英]Why won't this async/await run asynchronously?
我一直在尋找答案,但是根據許多指南和SO問題,該代碼對我來說仍然是正確的,但它可以同步運行。
private void CheckConditions()
{
foreach (var obj in myObjects)
{
if (obj.ConditionMet)
{
HandleConditionAsync(obj);
}
}
DoOtherWork();
}
private async void HandleConditionAsync(MyObject obj)
{
// shouldn't control transfer back to CheckConditions() here while we wait for user input?
string userInput = await obj.MessagePromptAsync("hello user");
DoSomeBookkeeping(obj);
}
// (MyObject.cs)
private MessagePrompt messagePrompt; // inherits from UserControl
public async Task<string> MessagePromptAsync(string prompt)
{
return await Task.FromResult<string>(messagePrompt.Prompt(prompt));
}
// (MessagePrompt.cs)
public string Prompt(string prompt)
{
this.UIThread(() => this.SetMessagePrompt(prompt));
userInputAutoResetEvent.WaitOne();
return myResult; // set in a button handler that also sets the AutoResetEvent
}
我打算讓CheckConditions()繼續愉快地運行,但是盡管我處於異步/喚醒狀態,但它仍卡在MessagePrompt的AutoResetEvent上。 我唯一能想到的是錯誤的是,由於UserControl的某些限制,其對UI線程引用的使用或堆棧頂部的非異步方法,MessagePrompt的方法可能無法異步運行。
您的代碼中沒有異步的東西。 您擁有的唯一任務是根據結果值創建的,這意味着Prompt()
方法必須完成並返回其結果,然后才能返回Task
對象以等待。 該對象將已經完成,因此一旦它具有要等待的Task
,所有await
對象都會立即完成。
也許您的意思是這樣的:
public async Task<string> MessagePromptAsync(string prompt)
{
return await Task.Run(() => messagePrompt.Prompt(prompt));
}
或者(如果您確實在MessagePromptAsync()
方法中沒有其他東西):
public Task<string> MessagePromptAsync(string prompt)
{
return Task.Run(() => messagePrompt.Prompt(prompt));
}
請注意,這可能會導致另一個問題,具體取決於DoOtherWork()
和UIThread()
實際操作。 如果您的UI線程陷入DoOtherWork()
,並且UIThread()
方法包裝了Dispatcher.Invoke()
或類似的東西,那么您將陷入僵局。
如果那不能解決您的問題,請提供一個可靠的最小,完整和可驗證的代碼示例 ,以可靠地重現該問題。
您還需要使CheckConditions()
異步,然后等待對HandleConditionAsync(MyObject obj)
的調用。 CheckConditions()
在您的示例中同步運行。
private async Task CheckConditionsAsync()
{
foreach (var obj in myObjects)
{
if (obj.ConditionMet)
{
await HandleConditionAsync(obj);
}
}
DoOtherWork();
}
另外,這只是最佳做法,異步方法應盡可能返回Task。 我唯一必須使用async void
是為了與事件處理程序兼容。 您可以看到我以這種方式更改了CheckConditions()
,並且應該類似地修改HandleConditionAsync(MyObject obj)
。 我還更改了方法名稱以表示它的異步行為。
如果您需要運行一種方法來同步返回Task
(並且您不應該這樣做,這表明您的設計有誤),則可以使用Task.FromResult(MyMethodAsync())
來運行它。 同樣,避免在任何可能的地方執行此操作,這首先使實現與方法異步的目的無效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.