异步调用同步方法比自然异步方法更快地完成任务

Jen*_*iya -4 c# task-parallel-library async-await

抱歉标题不好.我目前正在学习TPL并阅读这篇博客文章

异步调用同步方法的能力对可伸缩性没有任何作用,因为如果你同步调用它,你通常仍会消耗相同数量的资源(事实上,你使用的更多,因为它有开销因安排某事而招致).

所以我想让我们尝试一下,然后我创建了使用WebClient's DownloadStringTaskAsyncDownloadString(同步)方法的演示应用程序.

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

  1. DownloadHtmlNotAsyncInAsyncWay

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

  2. DownloadHTMLCSAsync

    这会调用异步方法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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

是dotnetfiddle链接.

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

SLa*_*aks 8

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

Task.WhenAll(tasks);返回Task所有这些任务的完成.
你没有对这项任务做任何事情,所以你不等待任何事情完成.

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