Async-await Task.Run vs HttpClient.GetAsync

von*_*dip 16 c# asynchronous task-parallel-library async-await c#-5.0

我是c#5异步功能的新手.我试图理解这两个实现之间的区别:

实施1:

private void Start()
{
    foreach(var url in urls)
    {
        ParseHtml(url);
    }
}

private async void ParseHtml(string url)
{
    var query = BuildQuery(url); //BuildQuery is some helper method
    var html = await DownloadHtml(query);
    //...
    MyType parsedItem = ParseHtml(html);
    SaveTypeToDB(parsedItem);
}

private async Task<string> DownloadHtml(string query)
{
    using (var client = new HttpClient())
    try
    {
        var response = await client.GetAsync(query);
        return (await response.Content.ReadAsAsync<string>());
    }
    catch (Exception ex)
    {
        Logger.Error(msg, ex);
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

实施2:

private void DoLoop()
{
    foreach(var url in urls)
    {
        Start(url);
    }
}

private async void Start(url)
{
    await Task.Run( () => ParseHtml(url)) ;
}

private void ParseHtml(string url)
{
    var query = BuildQuery(url); //BuildQuery is some helper method
    var html = DownloadHtml(query);
    //...
    MyType parsedItem = ParseHtml(html);
    SaveTypeToDB(parsedItem);
}

private string DownloadHtml(string query)
{
    using (var client = new WebClient())
    {
        try
        {
            return client.DownloadString(query);
        }
        catch (Exception ex)
        {
            Logger.Error(msg, ex);
            return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我宁愿使用第二个实现,因为它会在我的代码中对方法需要较少的"异步"签名.我试图了解使用HttpClient类与使用新任务并等待它的好处是什么?

这两种实现有什么区别吗?

Jon*_*eet 28

我宁愿使用第二个实现,因为它会在我的代码中对方法需要较少的"异步"签名.

这听起来像是一个非常奇怪的理由.你试图从根本上"稍微异步"执行 - 那么为什么不明白呢?

这两种实现有什么区别吗?

绝对.第二个实现将在WebClient.DownloadString块时占用一个线程,等待请求完成.第一个版本没有任何阻塞的线程 - 它依赖于在请求完成时触发的延续.

另外,考虑一下你的Logger.Error电话.在异步版本中,它仍将在原始调用代码的上下文中执行.因此,如果它位于Windows窗体UI中,您仍将位于UI线程上,并且您可以访问UI元素等.在第二个版本中,您将在线程池线程中执行,并且需要编组回UI线程以更新UI.

请注意,您的async void方法几乎肯定应该async void.您应该只为了遵守事件处理程序签名而async返回一个方法void.在所有其他情况下,返回Task- 调用者可以看到您的任务何时完成,处理异常等.

另请注意,您不需要使用HttpClient异步 - 您可以使用WebClient.DownloadStringTaskAsync,因此您的最终方法可能变为:

private async Task<string> DownloadHtml(string query)
{
    using (var client = new WebClient())
    {
        try
        {
            return await client.DownloadStringTaskAsync(query);
        }
        catch (Exception ex)
        {
            Logger.Error(msg, ex);
            return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Cor*_*son 6

对于服务器应用程序,async是关于最小化已经阻塞的线程数:提高线程池的效率,并允许您的程序扩展到更多用户.

对于您不太可能需要关心线程计数的客户端应用程序,async提供了一种相对简单的方法,可以在执行I/O时保持UI运行流畅.

Task.Run与引擎盖下方有很大不同.