假设我有一个非基于UI的应用程序(ASP.NET)和基于UI的应用程序(WinForm和WPF)的库。不幸的是,我不能避免混合IO绑定工作和CPU绑定工作,但我让消费者通过DummyWorkAsync
或不基于他们的应用程序类型(非UI或基于UI的应用程序)调用Task.Run
。
class DummyService
{
public static async Task<int> DummyWorkAsync()
{
// Do some I/O first.
await Task.Delay(1000);
// Tons of work to do in here!
for (int i = 0; i != 10000000; ++i)
;
// Possibly some more I/O here.
await Task.Delay(1000);
// More work.
for (int i = 0; i != 10000000; ++i)
;
return 0;
}
}
这允许基于UI的使用者正确使用Task.Run
来调用服务,而ASP.NET客户端将直接调用该方法,如下所示。
private async void MyButton_Click(object sender, EventArgs e)
{
await Task.Run(() => DummyService.DummyWorkAsync());
}
public class Home: Controller
{
public async Task<ActionResult> IndexAsync()
{
var result = await DummyService.DummyWorkAsync();
return View(result);
}
}
我对基于UI的应用感兴趣。如果我使用
有什么不同private async void MyButton_Click(object sender, EventArgs e)
{
await Task.Run(async () => await DummyService.DummyWorkAsync());
}
而不是
private async void MyButton_Click(object sender, EventArgs e)
{
await Task.Run(() => DummyService.DummyWorkAsync());
}
答案 0 :(得分:3)
不,没有(重大)差异。你基本上是在询问
之间的区别static Task<int> Something() {
return SomethingAsync();
}
和
static async Task<int> Something() {
return await SomethingAsync();
}
除了你的情况之外还有一个包装任务(Task.Run
),所以在这种情况下你可能在同一问题的另一个问题中找到的例外传播的差异是不相关的。
因此 - 只需使用
await Task.Run(() => DummyService.DummyWorkAsync());
那就是说,这样做的原因并不那么清楚。由于您的IO先行 - 您可以使用ConfigureAwait(false)
来防止将控制权返回到当前同步上下文(这对于库来说这是一个很好的做法)。在这种情况下,在您第一次等待其余(繁重的CPU工作)将在线程池线程(至少使用默认调度程序)上执行,因此您首先不需要使用Task.Run
:
public static async Task<int> DummyWorkAsync()
{
// Do some I/O first.
await Task.Delay(1000).ConfigureAwait(false);
// Tons of work to do in here!
// no problem, we are not on UI thread anyway
for (int i = 0; i != 10000000; ++i)
;
// Possibly some more I/O here.
await Task.Delay(1000).ConfigureAwait(false);
// More work.
for (int i = 0; i != 10000000; ++i)
;
return 0;
}