比较以下两种方法:
static async Task<int> DownloadAsync(string url)
{
var client = new WebClient();
var awaitable = client.DownloadDataTaskAsync(url);
byte[] data = await awaitable;
return data.Length;
}
用法:Task<int> task = DownloadAsync("http://stackoverflow.com");
static Task<int> Download(string url)
{
var client = new WebClient();
var task = client.DownloadDataTaskAsync(url);
byte[] data = task.Result;
return Task.FromResult(data.Length);
}
用法:
Task task = new Task(() => Download("http://stackoverflow.com"));
task.Start();
据我所知,两种方法都是异步运行的。我的问题是:
两种方法之间的行为有什么不同吗?
为什么我们更喜欢异步 - 等待其他它是一个很好的模式?
答案 0 :(得分:7)
您发布的两种方法完全不同。
DownloadAsync
是一种真正的异步方法。这意味着在下载数据时,该异步操作没有阻塞线程。
Download
通过调用Task.Result
同步阻止调用线程。我在我的博客why Result
should not be used with asynchronous Task
s上解释:在一般情况下,它可能导致死锁。但我们假设没有僵局。然后,您从TPL任务中调用它,因此它会阻止任务线程(很可能是线程池线程)。在下载数据时,该异步操作会阻止该任务线程。
因此,DownloadAsync
效率更高。
答案 1 :(得分:3)
new Task
将使用TaskScheduler.Current
执行整个方法,通常这会使用ThreadPool
。
通过使用async / await,该方法是同步进入的,并且只在需要时才使用异步延续。
我的意思可以通过以下LINQPad程序来证明:
const int delay = 1;
public async Task DoSomethingAsync()
{
Thread.CurrentThread.ManagedThreadId.Dump();
await Task.Delay(delay).ConfigureAwait(false);
Thread.CurrentThread.ManagedThreadId.Dump();
}
void Main()
{
DoSomethingAsync().Wait();
}
尝试将delay
更改为0,您将看到继续在同一个线程上恢复,这是因为Task.Delay
只是在没有延迟的情况下立即返回,这样可以避免安排的开销和在不需要时执行延续。
使用new Task
,即使异步方法的实现者可能认为不必要,您也会失去这个聪明的功能并始终使用ThreadPool
线程。
答案 2 :(得分:0)
看看这个post,Stephen Cleary确切地解释了原因和差异。
简而言之,它完全相同。这是新的与旧的等待方式。我发现async / await在眼睛上也更好,因为你将在另一个方法中获得额外的代码,而不需要放任务.Start()。