为什么这个 WebRequest 代码运行缓慢?

12

我请求了100页,但全部都是404。我写了:

    {
    var s = DateTime.Now;
    for(int i=0; i < 100;i++)
        DL.CheckExist("http://google.com/lol" + i.ToString() + ".jpg");
    var e = DateTime.Now;
    var d = e-s;
        d=d;
        Console.WriteLine(d);
    }

static public bool CheckExist(string url)
{
    HttpWebRequest wreq = null;
    HttpWebResponse wresp = null;
    bool ret = false;

    try
    {
        wreq = (HttpWebRequest)WebRequest.Create(url);
        wreq.KeepAlive = true;
        wreq.Method = "HEAD";
        wresp = (HttpWebResponse)wreq.GetResponse();
        ret = true;
    }
    catch (System.Net.WebException)
    {
    }
    finally
    {
        if (wresp != null)
            wresp.Close();
    }
    return ret;
}

运行两次得出所需时间分别为00:00:30.7968750和00:00:26.8750000。然后我尝试了Firefox,并使用以下代码:

<html>
<body>
<script type="text/javascript">
for(var i=0; i<100; i++)
    document.write("<img src=http://google.com/lol" + i + ".jpg><br>");
</script>

</body>
</html>

使用我的补休时间,大约需要4秒钟。4秒钟比我的应用程序快6.5-7.5倍。我计划扫描数千个文件,因此需要3.75小时而不是30分钟将是一个大问题。如何让这段代码更快?我知道有人会说Firefox缓存了图片,但我想说:1)它仍然需要检查来自远程服务器的标头以查看是否已更新(这正是我希望我的应用程序执行的)2)我没有收到正文,我的代码应该只请求标头。那么,我该怎么解决这个问题呢?

8个回答

52

我注意到一个HttpWebRequest在第一次请求时会挂起。我做了一些研究,发现问题出在请求正在配置或自动检测代理。如果你设置

request.Proxy = null;

在Web请求对象上,您可能可以避免初始延迟。

使用自动代理检测:

using (var response = (HttpWebResponse)request.GetResponse()) //6,956 ms
{
}

未使用代理自动检测:

request.Proxy = null;
using (var response = (HttpWebResponse)request.GetResponse()) //154 ms
{
}

当我在我的代码中加入这一行 request.Proxy = null;,我立即得到了结果!谢谢 - zidane
2
如果请求需要通过某些客户端站点的代理进行,会有什么后果?它是否仍然知道需要获取代理? - TheWommies
我不知道。代理自动检测似乎很慢(或者说,这已经超过两年了),所以我将其禁用了。我猜测如果设置了这个标志,它可能无法正确检测代理。 - Max
在凌晨1点,我正在调试线程代码,试图找出是什么原因导致某些请求如此缓慢。而“Proxy = null”拯救了我!非常感谢! - Gant
有时候,如果服务器/服务支持的话,将Expect100Continue设置为false可以加快Web请求的速度:ServicePointManager.Expect100Continue = false;https://msdn.microsoft.com/zh-cn/library/system.net.servicepointmanager.expect100continue(v=vs.110).aspx默认情况下,在每次查询之前都会发送一个Continue 100状态。通过禁用此功能,可以加快请求的速度。 - juFo
如果在操作系统级别上设置了代理,这个程序还会使用代理吗? - XaverB

4

请将您的代码更改为异步getresponse。

public override WebResponse GetResponse() {
    •••
    IAsyncResult asyncResult = BeginGetResponse(null, null);
    •••
    return EndGetResponse(asyncResult);
}

异步获取


2
是的,但现在你也可以用一行代码来完成。WebClient.DownloadSctringAsync http://msdn.microsoft.com/en-us/library/ms144202(VS.80).aspx - Chad Grant
如果你想要实现这个不仅仅是用于下载,这可能会有用 - cregox

2
也许Firefox会同时发出多个请求,而您的代码是一个接一个地执行。也许添加线程会加速您的程序。

好的观点。网站是否接受超过3个线程?这可能解释了为什么一个网站可能比原来快3-4倍,但不会超过6.5倍。嗯,我会记住这一点,今晚再试一次。 - user34537
所以我用另一个应用程序进行了检查,发现我测试的一个网站可以处理8个线程。这就可以解释了。如果这是唯一的原因,那我会有点尴尬。 - user34537
可能 Firefox 一次只发出 3 个请求。 - Artelius

1
答案是将HttpWebRequest/HttpWebResponse更改为WebRequest/WebResponse即可。这样就解决了问题。

0

当你完成时关闭响应流,所以在你的checkExist()函数中,在wresp = (HttpWebResponse)wreq.GetResponse()之后添加wresp.Close()。


0

您是否尝试在部署代码的机器上使用IE打开相同的URL?如果是Windows Server机器,则有时是因为您请求的URL不在IE(HttpWebRequest工作的基础)的安全站点列表中。您只需要添加它即可。

您是否有更多信息可以发布?我正在做类似的事情,并且以前遇到了大量HttpWebRequest问题。所有问题都是独特的。因此,更多信息将有所帮助。

顺便说一句,在这种情况下使用异步方法调用并不会真正有所帮助。它不会缩短下载时间。它只是不会阻塞您的调用线程而已。


我尝试使用IE6,它大约需要5秒钟。我的代码使用= wreq.Method =“HEAD”;需要12.5秒。我会认为是因为它使用了2个线程。那个数据看起来足够接近。 - user34537
注意到你提到了请求404页面。以前没有有意这样做过,但是在这种情况下 WebRequest 的行为可能不同。这值得研究一下。如果您使用GET请求现有页面,它是否需要正常的4秒钟? - Fung

0

设置Cookie很重要,您必须像这样添加AspxAutoDetectCookieSupport=1代码

 req.CookieContainer = new CookieContainer();         
 req.CookieContainer.Add(new Cookie("AspxAutoDetectCookieSupport", "1") { Domain = target.Host });

0

如果您在访问所有网页时都收到404状态码,则是因为未指定凭据。因此,您需要添加

wreq.Credentials = CredentialCache.DefaultCredentials;

然后,您可能还会遇到状态码= 500,为此需要指定用户代理。它看起来像下面这一行:

wreq.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0";

"WebClient实例默认不发送可选的HTTP头。如果您的请求需要一个可选的头部,您必须将该头部添加到Headers集合中。例如,为了保留响应中的查询,您必须添加一个用户代理头。此外,如果缺少用户代理头,服务器可能会返回500(内部服务器错误)。

参考:https://msdn.microsoft.com/en-us/library/system.net.webclient(v=vs.110).aspx

为了提高HttpWebRequest的性能,您需要添加

"
wreq.Proxy=null

现在代码将看起来像这样:

 static public bool CheckExist(string url)
{
    HttpWebRequest wreq = null;
    HttpWebResponse wresp = null;
    bool ret = false;

try
{
    wreq = (HttpWebRequest)WebRequest.Create(url);
    wreq.Credentials = CredentialCache.DefaultCredentials;
    wreq.Proxy=null;
    wreq.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0";
    wreq.KeepAlive = true;
    wreq.Method = "HEAD";
    wresp = (HttpWebResponse)wreq.GetResponse();
    ret = true;
}
catch (System.Net.WebException)
{
}
finally
{
    if (wresp != null)
        wresp.Close();
}
return ret;

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接