System.Net.WebClient 运行缓慢的原因

44

当使用System.Net.WebClient.DownloadData()方法时,我得到了一个非常慢的响应时间。

在.NET中使用WebClient类获取URL时,需要大约10秒才能获得响应,而使用浏览器获取同一页只需要不到1秒钟。而且这是在数据大小为0.5KB或更小的情况下。

请求涉及POST/GET参数和用户代理标头,如果可能会导致问题。

我还没有尝试过其他在.NET中下载数据的方式是否会给我带来同样的问题,但我怀疑我可能会得到类似的结果。(我一直觉得.NET中的Web请求异常缓慢...)

这可能是什么原因呢?

编辑:
我尝试使用System.Net.HttpWebRequest代替,使用以下方法进行,所有请求都在1秒钟内完成。

public static string DownloadText(string url)
        var request = (HttpWebRequest)WebRequest.Create(url);
        var response = (HttpWebResponse)request.GetResponse();

        using (var reader = new StreamReader(response.GetResponseStream()))
        {
            return reader.ReadToEnd();
        }
}


虽然这种使用System.Net.WebClient的(旧)方法需要15-30秒才能完成每个请求:

public static string DownloadText(string url)
{
       var client = new WebClient();
       byte[] data = client.DownloadData(url);
       return client.Encoding.GetString(data);
}

相关链接:https://dev59.com/HW445IYBdhLWcg3wTIjm - BlueRaja - Danny Pflughoeft
8个回答

88

我曾遇到使用WebRequest时的这个问题。尝试设置Proxy = null;

    WebClient wc = new WebClient();
    wc.Proxy = null;

默认情况下,WebClient和WebRequest会尝试从IE设置中确定使用哪个代理,有时会导致实际请求发送前延迟大约5秒。

这适用于所有使用WebRequest的类,包括使用HTTP绑定的WCF服务。通常情况下,您可以在应用程序启动时使用以下静态代码:

WebRequest.DefaultWebProxy = null;

3
我做了这个后,速度提升了很多。谢谢! - mpen
1
第二个对我的情况产生了巨大的影响!这绝对是这些Web代理的减速“特性”。 - Leni Kirilov
遇到了同样的问题,这真的提高了响应时间! - gigi
还可以在配置文件中设置:http://msdn.microsoft.com/zh-cn/library/kd3cf2ex.aspx - Alexander Selishchev
谢谢!这让我的速度翻了一倍。 - Curtis White
显示剩余2条评论

2

在这里下载Wireshark http://www.wireshark.org/

捕获网络数据包并过滤“http”数据包。这样就可以立即得到答案。


1
在wireshark上没有出现任何奇怪的情况,但是通过跟踪打印,我可以看到WebClient.DownloadData()被调用,而GET请求直到大约10-30秒后才出现在wireshark上(取决于“冻结”时间)。 看起来减慢速度的不是请求本身,而是在实际的GET请求之前完成的某些操作。 - moevi
1
看起来你的客户端正在等待某个超时。大多数情况下,它在等待DNS超时或NetBIOS超时。你可以尝试过滤DNS数据包和NetBIOS数据包。或者,你可以尝试通过源IP地址进行过滤。这应该能告诉你在GET请求之前你的客户端发送的最后一个数据包是什么。也许@Broken Pipe是对的。它可能在等待代理。 - Harvey Kwok

1

设置 WebRequest.DefaultWebProxy = null; 或者 client.Proxy = null 对我没有任何作用,在 iOS 上使用 Xamarin。

我做了两件事来解决这个问题:

我编写了一个不使用 WebRequest 和 System.Net 的 downloadString 函数:

        public static async Task<string> FnDownloadStringWithoutWebRequest(string url)
        {
            using (var client = new HttpClient())
            {
                //Define Headers
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                var response = await client.GetAsync(url);

                if (response.IsSuccessStatusCode)
                {
                    string responseContent = await response.Content.ReadAsStringAsync();
                    //dynamic json = Newtonsoft.Json.JsonConvert.DeserializeObject(responseContent);
                    return responseContent;
                }
                Logger.DefaultLogger.LogError(LogLevel.NORMAL, "GoogleLoginManager.FnDownloadString", "error fetching string, code: " + response.StatusCode);
                return "";
            }
        }

然而,使用Managed HttpClient仍然很慢。

因此,第二个步骤,在Visual Studio Community for Mac中,在解决方案中右键单击项目 -> 选项 -> HttpClient实现设置为NSUrlSession,而不是Managed

屏幕截图:将HttpClient实现设置为NSUrlSession而不是Managed

Managed没有完全集成到iOS中,不支持TLS 1.2,因此不支持iOS9+中默认设置的ATS标准,请参见此处:

https://learn.microsoft.com/en-us/xamarin/ios/app-fundamentals/ats

通过这两个更改,字符串下载始终非常快(<<1s)。 如果没有这两个更改,在每次第二或第三次尝试时,downloadString 都需要超过一分钟。


顺便提一下,虽然这不再是必要的,但你还可以尝试另外一件事情:

            //var authgoogle = new OAuth2Authenticator(...);
            //authgoogle.Completed...

            if (authgoogle.IsUsingNativeUI)
            {
                // Step 2.1 Creating Login UI 
                // In order to access SFSafariViewController API the cast is neccessary
                SafariServices.SFSafariViewController c = null;
                c = (SafariServices.SFSafariViewController)ui_object;
                PresentViewController(c, true, null);
            }
            else
            {
                PresentViewController(ui_object, true, null);
            }

虽然根据我的经验,你可能不需要SafariController。


很遗憾,这对安卓系统没有帮助。 - smedasn

1

.NET网络请求本身并不慢;你的代码应该没问题。我经常使用WebClient,速度非常快。

每个方向上的有效载荷有多大?这可能是一个愚蠢的问题,但是它只是带宽限制吗?

在我看来,最有可能的情况是你的网站已经停止运行,当你访问URL时,网站响应缓慢。这不是客户端的错。也有可能是DNS出了问题(在这种情况下,你可以将IP硬编码到你的“hosts”文件中),或者中间某个代理服务器很慢。

如果这个网站不是你自己的,他们可能会检测到非典型的使用情况,并故意注入延迟来干扰爬虫。

我建议你使用Fiddler(一个免费、简单的Web检查器)来查看时间。


1

如果在IE设置(连接选项卡 - LAN设置)中勾选了自动代理设置,WebClient可能会在某些工作站上变得很慢。


0

0
你用什么浏览器进行测试?
尝试使用默认的IE安装。System.Net.WebClient使用本地IE设置、代理等。也许被搞砸了?

0

WebClient下载速度极慢的另一个原因是你下载到的目标媒体。如果它是像USB键这样的慢设备,这可能会严重影响下载速度。我可以在我的HDD上以6MB/s的速度下载,但在我的USB键上只能以700kb/s的速度下载,尽管我可以从另一个驱动器以5MB/s的速度复制文件到这个USB。wget显示相同的行为。这也在这里报告:

https://superuser.com/questions/413750/why-is-downloading-over-usb-so-slow

所以如果这是您的情况,另一种解决方案是先下载到硬盘,然后在下载完成后将文件复制到慢速媒介中。


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