dra*_*gen 0 c# multithreading asynchronous async-await
我对C#上的整个Async/Await主题完全不熟悉.尽管有无数的问题得到解答,并且教程被无情地链接起来,但我仍然无法理解如何使用async/await.我想要实现的是wpf应用程序返回到UI上的渲染动画,同时它等待一个昂贵的方法调用来完成 - 在我的下面的例子中,那是GetLinesAsync()
或者更具体地说,expensive_function()
在:
void Button_Click(object sender, RoutedEventArgs e) {
MessageBox.Show(GetAMessage());
}
string GetAMessage() {
string ret = "";
foreach(string s in GetLinesAsync().Result)
ret += $"{s}\n";
return ret;
}
async Task<List<string>> GetLinesAsync() {
List<string> ret = new List<string>();
string[] ExpensiveResult = null;
if (await Task.Run(() => expensive_function(ref ExpensiveResult)) == expensive_stat.SUCCESS && ExpensiveResult != null)
{
foreach(string s in ExpensiveResult)
ret.Add(s);
}
Run Code Online (Sandbox Code Playgroud)
这样写,应用程序完全冻结,即使expensive_function()
执行时间不长.除此之外,我不确定为什么会发生这种情况,这是我从await/async上阅读教程和解释时所理解的,特别是那些说你只能等待返回void或Task的方法的部分:
该生产线foreach(string s in GetLinesAsync().Result)
实际上应该说foreach(string s in await GetLinesAsync().Result)
-但后来我不得不纪念GetMessages()
异步,然后我不得不更换MessageBox.Show(GetAMessage())
与MessageBox.Show(await GetMessages())
和标记Button_Click()
异步.
换句话说:awaitability会爬上调用堆栈,直到它达到void方法.好的,但那不可能,不是吗?如果在某些其他情况下,甚至没有可感知的无效方法可以实现呢?
你编码阻塞的原因是你在这里阻止它.
foreach(string s in GetLinesAsync().Result)
Run Code Online (Sandbox Code Playgroud)
你说UI线程等到我的昂贵任务完成
让asyn
c流畅.
在Windows窗体和WPF中,async
/ await
具有在您等待的异步操作完成时返回UI线程的便利属性
async
特别添加了对void方法的支持以支持事件处理程序.但是请确保您处理异常,因为无法观察到void
所以你可以这样做.
注意:这是一个基于您的代码的极其简化和消毒的示例
public async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
MessageBox.Show(await GetAMessage());
}
catch (Exception exception)
{
// log the nelly out of it
// or display message
}
}
public async Task<string> GetAMessage()
{
var list = await GetLinesAsync();
return string.Join("\n", list);
}
public List<string> ExpensiveFunction()
{
// ...
return new List<string>();
}
public async Task<List<string>> GetLinesAsync()
{
var result = Task.Run(() => ExpensiveFunction());
return await result;
}
Run Code Online (Sandbox Code Playgroud)