我们从一些现有的代码开始,它们以同步方式执行一些复杂计算。
class MyService
{
public int CalculateMandelbrot()
{
for (int i = 0; i != 10000000; ++i)
{
// 一些计算逻辑
}
return 100;
}
}
private void MyButton_Click(object sender, EVentArgs e)
{
// 会堵塞 UI 线程
myService.CalculateMandelbrot();
}
现在,我们想在 UI 线程中使用它,但是这个方法会堵塞我们的 UI 线程。这是一个应该使用 Task.Run 执行 CPU-bound 操作的地方。
为了不会堵塞 UI 线程,很多新手可能会以下面的方式使用 Task.Run
class MyService
{
public Task<int> CalculateMandelbrotAsync()
{
return Task.Run(()=>
{
for (int i = 0; i != 10000000; ++i)
{
// 一些计算逻辑
}
return 100;
})
}
}
private async void MyButton_Click(object sender, EVentArgs e)
{
// 不会堵塞 UI 线程
await myService.CalculateMandelbrot();
}
咋一看,这似乎解决了问题。它确实解决了这个问题,但是它并没有以最好的方式做到这一点。
class MyService
{
public int CalculateMandelbrotAsync()
{
for (int i = 0; i != 10000000; ++i)
{
// 一些计算逻辑
}
return 100;
}
}
private async void MyButton_Click(object sender, EVentArgs e)
{
// 不会堵塞 UI 线程
await Task.Run(() => { myService.CalculateMandelbrot(); });
}
现在的服务 API 是干净的(它为 CPU-bound 方法公开了一个同步 API),它适用于所有调用者,并且 UI 层负责不堵塞 UI 线程。
结论:不要在方法实现中使用 Task.Run;而是使用 Task.Run 来调用方法。