使用async / await比使用task.Start()更好吗?为什么?

时间:2013-11-17 00:52:40

标签: c# task async-await

比较以下两种方法:

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();

据我所知,两种方法都是异步运行的。我的问题是:
两种方法之间的行为有什么不同吗?
为什么我们更喜欢异步 - 等待其他它是一个很好的模式?

3 个答案:

答案 0 :(得分:7)

您发布的两种方法完全不同。

DownloadAsync是一种真正的异步方法。这意味着在下载数据时,该异步操作没有阻塞线程。

Download通过调用Task.Result同步阻止调用线程。我在我的博客why Result should not be used with asynchronous Tasks上解释:在一般情况下,它可能导致死锁。但我们假设没有僵局。然后,您从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()。