.NET HttpWebRequest速度与浏览器

我有一个关于.Net HttpWebRequest客户端(或WebClient,给出类似结果)的性能的问题。

如果我使用HttpWebRequest请求一个html页面(在本例中为news.bbc.co.uk)并分析应用程序读取响应的速度(使用HttpAnalyzer),这比浏览器慢得多(Firefox,Chrome) ,IE)请求相同的资源(清除所有缓存等)。 .Net应用程序大约需要1.7秒,而浏览器需要0.2 – 0.3秒。

这纯粹取决于代码/应用程序的速度和效率,还是还有其他因素需要考虑?

代码如下:

HttpWebRequest request = null; Uri uriTest = new Uri("http://news.bbc.co.uk"); request = (HttpWebRequest)WebRequest.Create(uriTest); request.Method = "GET"; request.KeepAlive = true; request.Headers["Accept-Encoding"] = "gzip, deflate"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); response.Close(); 

如果您提出两个请求,第二个请求会更快发生吗?

我还注意到浏览器和WebClient或WebRequest之间的速度差异。 甚至响应的原始速度也可能完全不同 – 但并非总是如此!

这可能是由以下原因引起的:

  • 它可能是所有发生的.Net引导。 .Net程序集在使用之前不会加载和JIT,因此即使应用程序本身已经运行了很长时间,您也可以看到对一段代码的初始调用显着降低速度。 好的 – 所以.Net框架本身就是nGen’d – 但是你的代码和.Net框架之间仍然存在着动态构建的桥梁。

  • 只是检查你是否在没有连接调试器的情况下运行,并且你肯定没有打开符号服务器 – 符号服务器和VS会在下载符号时中断程序,从而减慢它们的负载。 对不起,如果这是侮辱;)

  • 浏览器被编码为仅有效地使用少数底层套接字; 一旦浏览器出现,它们就会被打开并启动。 使用.Net WebClient / WebRequest的“我们的”代码相比之下效率非常低,因为每次都会重新初始化所有内容。

  • 有很多与网络相关的平台资源,虽然.Net使得使用网络编码变得更加容易,但它仍然受到相同的平台资源问题的束缚。 因此,您越接近平台,一些代码就越快。 IE和Firefox等是原生的,因此本身可以抛出系统资源; .Net不是,因此需要一些编组(=慢)来设置。 显然,一旦港口被打开并被使用,.Net仍然没有懈怠; 但它几乎永远不会像编写良好的非编组本机代码一样快。

第一次请求页面时,.net会尝试检测代理设置。 解决方案是传入一个空的WebProxy对象。 这样它只是连接到远程服务器而不是自动检测代理服务器。

 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriTest); request.Proxy = new WebProxy(); 

您是否在使用浏览器时观看了网络? 也许浏览器正在使用缓存资源?

我在中间插入Fiddler ,一个接一个地运行浏览器请求和.NET请求,并确保你真正得到你的想法。 这可能是重定向或其他一些正在发生的事情(可能是浏览器预先附加’/’而.NET等待redir等),这些都不是立即可见的。 我在.NET HTTP客户端上构建了巨大的应用程序,没有你所描述的那样 – 其他必须要进行的事情。

如果你在url的末尾粘贴’/’会怎样?

使用Ctrl + F5而不是F5(调试模式)运行应用程序。 你会看到一个区别:

 class Program { static void Main() { using (var client = new WebClient()) { Stopwatch watch = Stopwatch.StartNew(); var data = client.DownloadData("http://news.bbc.co.uk"); watch.Start(); Console.WriteLine("{0} ms", watch.ElapsedMilliseconds); } } } 

在我的电脑上打印880毫秒。

什么是1.7s的细分? 我怀疑你在测量整个过程?

使用这段代码我平均得到大约200ms:

 var request = (HttpWebRequest)WebRequest.Create("http://www.bbc.co.uk/news/"); var stopwatch = new Stopwatch(); stopwatch.Start(); using (var response = (HttpWebResponse)request.GetResponse()) { stopwatch.Stop(); Console.WriteLine("Elapsed: {0}ms", stopwatch.ElapsedMilliseconds); var responseStream = response.GetResponseStream(); if (responseStream != null) using (var sr = new StreamReader(responseStream)) Console.WriteLine("Title: {0}", Regex.Match(sr.ReadToEnd(), @"title>(.*) 

编辑更改了代码只是为了测量实际的 HTTP请求,并尝试使用Fiddler:

上面的程序:经过:78ms

提琴手:整体经历:00:00:00.0620000

也许bbc.co.uk会检查传递给它的User-Agent标头并根据它来处理响应。 因此,如果它看到自动客户端,那么它响应缓慢,就好像它认为在线路末端有一个真人,然后它加速。 如果你真的想尝试一下,只需告诉HttpWebRequest传递一个不同的标题。

无论何时测量任何东西,都必须考虑启动成本。 如果您的.net代码只在一个过程中,并且您只测量单个请求,那么您的测量将受到初始化程序集,类型等的首次成本的影响。

正如达林和其他人所建议的那样,你应该确保:

1)您没有在debuggger下运行该进程。 2)您考虑了启动成本。

你可以做#2的一种方法是发出两个请求,只测量第二个请求。 或者您可以发出N个请求,丢弃第一个请求,并获得最后N-1个请求的平均值。 还要确保您已阅读实体流。

Markos的回答对我来说同样适用于同一个问题:

 request.Proxy = new WebProxy(); 

将16秒的请求减少到不到一秒钟。 谢谢!