抱歉标题不好。我目前正在学习TPL并阅读this博客文章,其中说明了
异步调用同步方法的能力对可伸缩性没有任何作用,因为如果你同步调用它,你通常仍会消耗相同数量的资源(事实上,你使用的更多,因为安排某些事情会产生开销。
所以我想让我们尝试一下,然后我创建了使用WebClient
DownloadStringTaskAsync
和DownloadString
(同步)方法的演示应用程序。
我的演示应用程序有两种方法
DownloadHtmlNotAsyncInAsyncWay
这提供了围绕同步方法DownloadString
的异步方法包装器,它不应该扩展良好。
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);
}
}
Here是dotnetfiddle链接。
为什么第一个选项在比第二次更短的时间内完成?
答案 0 :(得分:8)
你实际上并没有测量任何东西。
Task.WhenAll(tasks);
返回完成所有这些任务的Task
你没有做任何事情,所以你不等任何事情要完成。
因此,您只需测量每个备选方案的同步初始化。 Task.Run()
只是将一个委托排队到线程池;它比设置HTTP请求的工作少。
答案 1 :(得分:0)
事实上,你使用的更多,因为安排某些事情会产生开销
正如SLaks所建议的那样,即使您正确等待任务,也几乎无法准确衡量这一开销。
您的测试正在下载需要网络访问权限的网页。 您尝试测量的开销 soooo 远小于网络延迟的差异,它会在噪声中丢失。