为什么这个async/await不能异步运行?
本文关键字:不能 异步 运行 await async 为什么 | 更新日期: 2023-09-27 18:05:07
我已经搜索了这个问题的答案,但是根据许多指南和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上,尽管我的异步/等待。我能想到的唯一一件事可能是错误的是,也许MessagePrompt的方法不能异步运行,由于一些限制从UserControl,它使用的UI线程引用,或者可能在堆栈顶部的非异步方法。
您的代码中没有任何异步内容。您拥有的唯一任务是从结果值创建的,这意味着Prompt()
方法必须完成并返回其结果,然后才能返回Task
对象以等待。该对象将已经完成,因此它上面的任何await
都将立即完成,一旦它有Task
等待。
也许你的意思是:
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();
}
另外,这只是一个最佳实践的事情,一个异步方法应该总是返回一个任务在可能的时候。我唯一一次使用async void
是为了与事件处理程序兼容。你可以看到我这样修改了CheckConditions()
, HandleConditionAsync(MyObject obj)
也应该这样修改。我还更改了方法名称,以表示它的异步行为。
如果您需要运行一个同步返回Task
的方法(您不应该这样做,这表明您的设计存在错误),您可以使用Task.FromResult(MyMethodAsync())
运行它。同样,尽可能避免这样做,因为它首先违背了使方法异步化的目的。