ror*_*.ap 8 .net c# asynchronous task-parallel-library async-await
我一直在关注这个问题,我理解Peter Duniho的流行(尽管尚未接受)答案背后的原因.具体来说,我知道不等待后续的长时间运行将阻止UI线程:
第二个示例在异步操作期间不会产生.相反,通过获取content.Result属性的值,可以强制当前线程等待异步操作完成.
为了我自己的利益,我甚至证实了这一点,如下:
private async void button1_Click(object sender, EventArgs e)
{
var value1 = await Task.Run(async () =>
{
await Task.Delay(5000);
return "Hello";
});
//NOTE: this one is not awaited...
var value2 = Task.Run(async () =>
{
await Task.Delay(5000);
return value1.Substring(0, 3);
});
System.Diagnostics.Debug.Print(value2.Result); //thus, UI freezes here after 5000 ms.
}
Run Code Online (Sandbox Code Playgroud)
但现在我想知道:你是否需要await在最外面的等待操作中嵌套所有"等待"的操作?例如,我可以这样做:
private async void button1_Click(object sender, EventArgs e)
{
var value0 = await Task.Run(() =>
{
var value1 = new Func<Task<string>>(async () =>
{
await Task.Delay(5000);
return "hello";
}).Invoke();
var value2 = new Func<string, Task<string>>(async (string x) =>
{
await Task.Delay(5000);
return x.Substring(0, 3);
}).Invoke(value1.Result);
return value2;
});
System.Diagnostics.Debug.Print(value0);
}
Run Code Online (Sandbox Code Playgroud)
或者我可以这样做:
private async void button1_Click(object sender, EventArgs e)
{
//This time the lambda is async...
var value0 = await Task.Run(async () =>
{
//we're awaiting here now...
var value1 = await new Func<Task<string>>(async () =>
{
await Task.Delay(5000);
return "hello";
}).Invoke();
//and we're awaiting here now, too...
var value2 = await new Func<string, Task<string>>(async (string x) =>
{
await Task.Delay(5000);
return x.Substring(0, 3);
}).Invoke(value1);
return value2;
});
System.Diagnostics.Debug.Print(value0);
}
Run Code Online (Sandbox Code Playgroud)
他们都没有冻结UI.哪个更好?
i3a*_*non 13
最后一个是可取的(虽然非常凌乱)
在TAP(基于任务的异步模式)中,任务(和其他等待的)表示异步操作.您基本上有3个处理这些任务的选项:
DoAsync().Result,DoAsync().Wait()) - 阻止调用线程,直到任务完成.使您的应用程序更加浪费,可扩展性更低,响应更少,并且容易出现死锁.await DoAsync()) - 不阻塞调用线程.await在等待任务完成之后,它基本上在作为继续执行之后注册工作.DoAsync()) - 不阻塞调用线程,但也不等待操作完成.您不知道DoAsync处理时抛出的任何异常具体来说,我知道不等待随后的长时间运行将阻止UI线程
所以,不完全.如果你根本不等,什么都不会阻止但是你无法知道操作何时或是否成功完成.但是,如果您同步等待,则会阻塞调用线程,如果您阻止UI线程,则可能会出现死锁.
结论:await只要可能(Main例如,不是这样),你就应该等待.这包括"嵌套async-await操作".
关于您的具体示例:Task.Run用于将CPU绑定的工作卸载到ThreadPool线程,这似乎不是您试图模仿的.如果我们Task.Delay用来表示真正的异步操作(通常是I/O绑定),我们就可以"嵌套async-await"而不用Task.Run:
private async void button1_Click(object sender, EventArgs e)
{
var response = await SendAsync();
Debug.WriteLine(response);
}
async Task<Response> SendAsync()
{
await SendRequestAsync(new Request());
var response = await RecieveResponseAsync();
return response;
}
async Task SendRequestAsync(Request request)
{
await Task.Delay(1000); // actual I/O operation
}
async Task<Response> RecieveResponseAsync()
{
await Task.Delay(1000); // actual I/O operation
return null;
}
Run Code Online (Sandbox Code Playgroud)
您可以使用匿名委托而不是方法,但是当您需要定义类型并自己调用它们时会感到不舒服.
如果确实需要将该操作卸载到ThreadPool线程,只需添加Task.Run:
private async void button1_Click(object sender, EventArgs e)
{
var response = await Task.Run(() => SendAsync());
Debug.WriteLine(response);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1181 次 |
| 最近记录: |