我对.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();
答案 0 :(得分:2)
如果您提出两个请求,第二个请求会更快发生吗?
我还注意到浏览器与WebClient或WebRequest之间的速度差异。甚至响应的原始速度也可能大不相同 - 但并非总是如此!
这可能是由以下几点引起的:
可能会发生所有.Net引导。 .Net程序集在使用之前不会加载和JIT,因此即使应用程序本身已经运行了很长时间,您也可以看到对一段代码的初始调用显着降低速度。好的 - 所以.Net框架本身就是nGen'd - 但是你的代码和.Net框架之间仍然存在着动态构建的桥梁。
只是检查您是否在没有连接调试器的情况下运行,并且您肯定没有打开符号服务器 - 符号服务器和VS会在下载符号时中断程序,从而减慢它们的负载。对不起,如果这是侮辱;)
浏览器的编码只能有效地使用少量底层套接字;一旦浏览器出现,它们就会被打开并启动。使用.Net WebClient / WebRequest的“我们的”代码相比之下完全没有效率,因为每次都会重新初始化所有内容。
网络中有很多平台资源,虽然.Net使网络编码变得更加容易,但仍然存在相同的平台资源问题。因此,您越接近平台,一些代码就越快。 IE和Firefox等是原生的,因此本身可以抛出系统资源; .Net不是,因此需要一些编组(=慢)来进行设置。显然,一旦港口被打开并被使用,.Net仍然没有懈怠;但它几乎不会像编写良好的非编组本机代码一样快。
答案 1 :(得分:2)
首次请求页面时,.net会尝试检测代理设置。解决方案是传入一个空的WebProxy对象。这样它只是连接到远程服务器而不是自动检测代理服务器。
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriTest);
request.Proxy = new WebProxy();
答案 2 :(得分:1)
您在使用浏览器时是否看过网络?也许浏览器正在使用缓存资源?
答案 3 :(得分:1)
我在中间插入Fiddler,一个接一个地运行浏览器请求和.NET请求,并确保你真正得到你的想法。这可能是重定向或其他一些正在发生的事情(可能是浏览器预先附加'/'而.NET等待redir等),这些都不是立即可见的。我已经在.NET HTTP客户端上构建了巨大的应用程序,没有你所描述的那样 - 其他必须要进行的事情。
如果您在网址末尾加上“/”会怎样?
答案 4 :(得分:1)
1.7s的细分是什么?我怀疑你是在衡量整个过程吗?
使用这段代码我平均得到大约200毫秒:
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>(.*)</title").Groups[1].Value);
}
编辑 更改了代码,只是为了衡量实际的 HTTP请求,并尝试使用Fiddler:
上面的程序:经过时间:78毫秒
小提琴手:整体经历时间:00:00:00.0620000
答案 5 :(得分:1)
使用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毫秒。
答案 6 :(得分:0)
也许bbc.co.uk会检查传递给它的User-Agent
header并根据它来处理响应。因此,如果它看到自动化客户端,那么它响应缓慢,就好像它认为在线路末端有真人,然后它加速。如果你真的想尝试一下,只需告诉HttpWebRequest传递一个不同的标题。
答案 7 :(得分:0)
每当您测量任何东西时,您都必须考虑启动成本。如果.net代码在一个进程中,并且您只测量单个请求,那么初始化程序集,类型等的初始成本会影响您的测量。
正如达林和其他人所建议的那样,你应该确保:
1)您没有在debuggger下运行该进程。 2)您考虑了启动成本。
你可以做#2的一种方法是发出两个请求,只测量第二个请求。或者您可以发出N个请求,丢弃第一个请求,并获得最后N-1个请求的平均值。还要确保您已阅读实体流。
答案 8 :(得分:0)
Markos的答案对我来说同样适用于同一个问题:
request.Proxy = new WebProxy();
将16秒的请求减少到不到一秒钟。谢谢!