【问题标题】:Invoking synchronous method asynchronously completes task faster than natural async methods [closed]异步调用同步方法比自然异步方法更快地完成任务[关闭]
【发布时间】:2015-07-15 07:55:02
【问题描述】:

抱歉标题不好。我目前正在学习 TPL 并阅读 this 博客文章,其中指出

异步调用同步方法的能力对可伸缩性没有任何帮助,因为您通常仍会消耗与同步调用它相同数量的资源(实际上,您使用的资源要多一点,因为安排某些事情会产生开销)。

所以我想让我们试一试,我创建了使用WebClientDownloadStringTaskAsyncDownloadString(同步)方法的演示应用程序。

我的演示应用程序有两种方法

  1. 下载HtmlNotAsyncInAsyncWay

    这提供了围绕同步方法DownloadString 的异步方法包装器,它不应该很好地扩展。

  2. 下载HTMLCSAsync

    这会调用异步方法 DownloadStringTaskAsync。

我从这两种方法创建了 100 个任务并比较了消耗的时间,发现选项 1 消耗的时间比第二个要少。为什么?

这是我的代码。

using System;
using System.Diagnostics;
using System.Net;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        const int repeattime = 100;
        var s = new Sample();
        var sw = new Stopwatch();
        var tasks = new Task<string>[repeattime];
        sw.Start();
        for (var i = 0; i < repeattime; i++)
        {
            tasks[i] = s.DownloadHtmlNotAsyncInAsyncWay();
        }

        Task.WhenAll(tasks);
        Console.WriteLine("==========Time elapsed(non natural async): " + sw.Elapsed + "==========");
        sw.Reset();
        sw.Start();
        for (var i = 0; i < repeattime; i++)
        {
            tasks[i] = s.DownloadHTMLCSAsync();
        }

        Task.WhenAll(tasks);
        Console.WriteLine("==========Time elapsed(natural async)    : " + sw.Elapsed + "==========");
        sw.Reset();
    }
}

public class Sample
    {
        private const string Url = "https://www.google.co.in";

        public async Task<string> DownloadHtmlNotAsyncInAsyncWay()
        {
            return await Task.Run(() => DownloadHTML());
        }

        public async Task<string> DownloadHTMLCSAsync()
        {
            using (var w = new WebClient())
            {
                var content = await w.DownloadStringTaskAsync(new Uri(Url));
                return GetWebTitle(content);
            }
        }

        private string DownloadHTML()
        {
            using (var w = new WebClient())
            {
                var content = w.DownloadString(new Uri(Url));
                return GetWebTitle(content);
            }
        }

        private static string GetWebTitle(string content)
        {
            int titleStart = content.IndexOf("<title>", StringComparison.InvariantCultureIgnoreCase);
            if (titleStart < 0)
            {
                return null;
            }
            int titleBodyStart = titleStart + "<title>".Length;
            int titleBodyEnd = content.IndexOf("</title>", titleBodyStart, StringComparison.InvariantCultureIgnoreCase);
            return content.Substring(titleBodyStart, titleBodyEnd - titleBodyStart);
        }
    }

Here 是 dotnetfiddle 链接。

为什么第一个选项比第二次完成的时间短?

【问题讨论】:

    标签: c# async-await task-parallel-library


    【解决方案1】:

    你实际上并没有测量任何东西。

    Task.WhenAll(tasks); 返回完成所有这些任务的Task
    您无需对该任务执行任何操作,因此您无需等待任何事情完成。

    因此,您只是在测量每个备选方案的同步初始化。 Task.Run() 只是将委托排队到线程池;它的工作量比设置 HTTP 请求要少。

    【讨论】:

    • 我补充一下,试试Task.WaitAll
    • 天哪。这么愚蠢的问题。看来我需要像 Task.WhenAll(tasks).Wait(); 一样调用 wait 来测量消耗的时间......
    • @JenishRabadiya 或者,按照 Yorye 的建议使用 Task.WaitAll
    【解决方案2】:

    事实上,你使用的有点多,因为调度某些东西会产生开销

    即使您按照 SLaks 的建议正确地等待任务,也几乎不可能准确测量此开销。

    您的测试正在下载一个需要网络访问的网页。 您尝试测量的开销soooo远小于网络延迟的方差,因为它会在噪音中丢失。

    【讨论】:

      猜你喜欢
      • 2018-10-10
      • 2015-03-08
      • 2020-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-23
      • 1970-01-01
      相关资源
      最近更新 更多