首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Async-await Task.Run与HttpClient.GetAsync

Async-await Task.Run与HttpClient.GetAsync
EN

Stack Overflow用户
提问于 2012-11-24 06:40:38
回答 3查看 22K关注 0票数 16

我不熟悉c# 5的异步功能。我正在尝试理解这两个实现之间的区别:

实现1:

代码语言:javascript
复制
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;
    }
}

实现2:

代码语言:javascript
复制
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;
        }
    }
}

我宁愿使用第二个实现,因为它在我的代码中需要较少的“异步”签名。我正在尝试理解使用HttpClient类与使用新任务并等待它相比有什么好处?

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-11-24 06:59:06

我宁愿使用第二个实现,因为它在我的代码中需要更少的方法的“异步”签名。

这听起来像是一个非常奇怪的理由。你试图从根本上“有点异步”地执行--所以为什么不把这一点说清楚呢?

这两种实现有什么不同吗?

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

此外,考虑您的Logger.Error调用。在异步版本中,它仍将在原始调用代码的上下文中执行。因此,如果这是在Windows窗体UI中,那么您将仍然在UI线程上,并且您可以访问UI元素等。在第二个版本中,您将在线程池线程中执行,并且需要封送回UI线程来更新UI。

请注意,您的async void方法几乎肯定不应该为async void。您应该只为了符合事件处理程序签名的目的而使async方法返回void。在所有其他情况下,返回Task -这样调用者就可以看到你的任务何时完成,处理异常等。

还请注意,您不需要使用HttpClient进行异步--您可以使用WebClient.DownloadStringTaskAsync,因此您的最后一个方法可以变成:

代码语言:javascript
复制
private async Task<string> DownloadHtmlAsync(string query)
{
    using (var client = new WebClient())
    {
        try
        {
            return await client.DownloadStringTaskAsync(query);
        }
        catch (Exception ex)
        {
            Logger.Error(msg, ex);
            return null;
        }
    }
}
票数 29
EN

Stack Overflow用户

发布于 2012-11-25 01:27:26

对于服务器应用程序,async旨在最小化阻塞线程的数量:提高线程池的效率,也许还允许您的程序扩展到更多的用户。

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

它与底层的Task.Run有很大的不同。

票数 6
EN

Stack Overflow用户

发布于 2015-08-10 19:53:07

只有当您的调用线程有一些有意义的事情要做时,您才能从异步处理中受益,比如保持UI响应。如果您的调用线程只启动一个任务,并且只等待任务完成,则您的进程将运行较慢。

您的第二个实现启动了一个任务,但是您等待它完成,而不做其他任何事情。这样你就不会受益了。

您没有描述您的环境,但是如果您有一个必须保持响应的UI,那么方法1的实现是可以的,除了您的Start()没有被声明为async并且不等待:

代码语言:javascript
复制
private async Task StartAsync()
{
    foreach (var url in urls)
    {
        await ParseHtml(url)
    }
}

您可以从事件处理程序中调用它,如下所示:

代码语言:javascript
复制
private async void OnButton1_clicked(object sender, ...)
{
   await StartAsync();
}

注意: ParseHtml has的前面是await。下一个html将在前一个解析完成后被解析。然而,因为解析是异步的,所以调用线程(UI线程?)将能够做其他事情,如响应用户输入。

但是,如果您的parseHTML函数能够同时运行,则使用以下代码会更好,而且可能会更快:

代码语言:javascript
复制
private async Task StartAsync()
{
    var tasks = new List<Task>()
    foreach (var url in urls)
    {
        tasks.Add(ParseHtml(url));
    }
    // now you have a sequence of Tasks scheduled to be run, possibly simultaneously.
    // you can do some other processing here
    // once you need to be certain that all tasks are finished await Task.WhenAll(...)
    await Task.WhenAll(tasks);
    // Task.WhenAls(...) returns a Task, hence you can await for it
    // the return of the await is a void
}

  • 如果调用返回任务的函数,则可以在任务运行时继续执行其他操作,或者等待任务完成并使用任务的结果。
  • 如果等待,代码将停止,但调用者将继续处理,直到它们等待任务完成
  • 如果过程是异步的,则只能在过程中等待。
  • async函数只能由其他异步函数调用,或通过调用Task.Run ( ) => ...)或者如果您愿意,也可以这样做: Task.Factory.StartNew( () => ...)
  • 异步函数返回
  • 而不是void异步函数返回TResult唯一的异常是事件处理程序:将其声明为async并返回void。
  • 如果需要任务完成,只需等待任务。
  • 等待的返回是TResult。

<

  • >F223
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13536505

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档