以下引自Using the Built-in Task-based Combinators部分。
public async void button1_Click(object sender, EventArgs e)
{
pictureBox1.Image = await Task.Run(async() =>
{
using(Bitmap bmp1 = await DownloadFirstImageAsync())
using(Bitmap bmp2 = await DownloadSecondImageAsync())
return Mashup(bmp1, bmp2);
});
}
根据我从其他资源中读到的内容,IO绑定的异步方法不应该用Task.Run
包装,因为“我们不需要生成另一个线程来等待IO绑定操作完成”。
看起来上面的代码和我从其他人那里读到的概念是矛盾的。你能告诉我哪一个是正确的吗?
值得注意的是,Task.Run
在实际的SynchronizationContext
通话中丢弃了你的UI的Run()
。你可以很好地摆脱全球Task.Run
,简单地await First
,await Second
,然后Task.Run
只有Mashup
部分(如果我们保持这种方法是CPU绑定的假设),但微妙的区别是你会做往返您的UI线程的Dispatcher在每个等待之间(假设它们是异步完成的,考虑到它是下载操作,它们很可能会这样做)。
换句话说,这里的Task.Run
具有将UI线程从无用的跳转中保存的优点。在这个过度简化的示例中,这可以说完全可以忽略不计,但在现实场景中需要牢记这一点。你不希望你宝贵的UI线程不断地进行异步簿记操作,不管它们是多么短暂。通用工作线程池非常适合每秒执行数百万个线程切换,然后您的UI线程可以只花时间在实际的UI事物上。