使用代理的c#多线程网页下载-性能问题

本文关键字:下载 性能 问题 网页 多线程 代理 | 更新日期: 2023-09-27 18:05:51

我正在制作一个多线程代理检查器,我有自己的多线程算法,基本上启动了一堆线程(50+),每个线程连接到一个网页,只是简单地下载和检查响应。如果响应包含特定字符串,则假定代理正在工作。现在,当50个线程中的每一个都试图同时下载网页时,问题就出现了。网页本身的大小为400kb,因此使用代理下载可能需要一些时间。在没有代理的情况下,我几乎可以在短时间内得到50个结果。但是使用代理时,我以2或3个"批量"的方式获得结果,而且速度太慢了。我使用一个带有小超时的简单WebClient对象。我有一个100Mbit的连接,但它只使用了10%。我试着在网上找到一些解决方案,但没有运气。代码的多线程部分工作没有任何问题,因为我之前在许多项目中使用过它,并且它被完善了。

我发现所有的50个线程最终到达同一行代码(在完全相同的时间),下载页面的源代码,但随后停止。

    result = webClient.DownloadString(url);

我在这行中添加了一个简单的before和after计时器来测试下载所需的时间。人们会假设它不会超过5秒(因为这是超时)。计时器很长,而且会堆积起来(甚至高达120秒)。所以我猜活动连接的数量是有限制的。由于我有50个线程同时运行,我也希望一次下载50个页面,而不是等待前一个页面完成。

我试过使用:

    System.Net.ServicePointManager.DefaultConnectionLimit = int.MaxValue;

没有运气。这是我的代码:

    public class AwesomeWebClient : WebClient
    {
        protected override WebRequest GetWebRequest(Uri address)
        {
            WebRequest request = base.GetWebRequest(address);
            request.Timeout = 5000;
            HttpWebRequest webRequest = request as HttpWebRequest;
            return request;
        }
    }
    private static string Get(string url, string proxy, string UA)
    {
        string result = "";
        try
        {
            var webClient = new AwesomeWebClient();
            webClient.Headers.Add("Referer", "http://yahoo.com");
            webClient.Headers.Add("X-Requested-With", "XMLHttpRequest");
            webClient.Headers.Add("Accept", "*");
            webClient.Headers.Add("User-Agent", UA);
            webClient.Proxy = new WebProxy(proxy);
            result = webClient.DownloadString(url);
        }
        catch (Exception x)
        {
            //Console.WriteLine(x.Message + " | " + url);
        }
        return result;
    }

使用代理的c#多线程网页下载-性能问题

WebClient的幕后有很多东西,其中任何一个都可能成为瓶颈。毕竟,WebClient只是HttpWebRequest的一个方便的包装。这里可能导致问题的一件事是DNS解析,它可能限制您可以发出的并发请求的数量。虽然我看不出它会导致你所说的那种减速。

但问题很可能是线程。在单线程模型中,只有一个线程一次获取一个文档。它可以很快完成。如果有50个线程,就会有线程上下文切换的开销。所以一个线程得到几十千字节,但是它被交换给下一个线程。上下文切换的开销会减慢速度。

你应该考虑减少线程的数量。如果使用两个线程执行此操作会发生什么?那么四个线程呢?如果你限制线程上下文切换的数量,你将加快你的程序。

你可以尝试的另一件事是DownloadStringAsync,尽管这样你应该限制并发请求的数量。

最后,我不知道这是否仍然是真的,但在过去,创建一次WebClient并将其用于多个文件比为每次下载创建一个新的WebClient要快得多。也就是这段代码:

WebClient myClient = new WebClient();
foreach (var url in urlsList)
{
    myClient.DownloadString(url);
}

明显比下面的代码快:

foreach (var url in urlsList)
{
    WebClient myClient = new WebClient();
    myClient.DownloadString(url);
}

我从来没有追查到原因,我看到一些人说,情况不再是这样了。