首次失败后,获取HTML响应失败

时间:2016-08-28 11:12:33

标签: c# .net httpwebrequest webrequest httpwebresponse

我有一个程序,每5分钟获取~500个网页的HTML代码

它正常运行直到第一次失败(无法在6秒内下载源)

之后所有线程都将失败

如果我重新启动程序,它会再次正常运行,直到......

我错了,我应该做些什么来做得更好?

此功能每5分钟运行一次:

        foreach (Company company in companies)
        {
            string link = company.GetLink();

            Thread t = new Thread(() => F(company, link));
            t.Start();
            if (!t.Join(TimeSpan.FromSeconds(6)))
            {
                Debug.WriteLine( company.Name + " Fails");
                t.Abort();
            }
        }

此函数下载HTML代码

private void F(Company company, string link)
    {
        try
        {
            string htmlCode = GetInformationFromWeb.GetHtmlRequest(link);
            company.HtmlCode = htmlCode;
        }
        catch (Exception ex)
        {
        }
    }

和这堂课:

public class GetInformationFromWeb
{
    public static string GetHtmlRequest(string url)
    {
        using (MyWebClient client = new MyWebClient())
        {
            client.Encoding = Encoding.UTF8;
            string htmlCode = client.DownloadString(url);
            return htmlCode;
        }
    }
}

和Web客户端类

public class MyWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
        request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
        return request;
    }
}

2 个答案:

答案 0 :(得分:1)

如果您的foreach正在循环超过500家公司,并且每个公司都在创建一个新线程,那么您的互联网速度可能会成为瓶颈,您将在6秒内收到超时,并且经常会失败。

我建议你试试并行性。注意MaxDegreeOfParallelism,它设置最大并行执行量。您可以调整它以满足您的需求。

 Parallel.ForEach(companies, new ParallelOptions { MaxDegreeOfParallelism = 10 }, (company) =>
            {
                try
                {
                    string htmlCode = GetInformationFromWeb.GetHtmlRequest(company.link);
                    company.HtmlCode = htmlCode;
                }
                catch(Exception ex)
                {
                    //ignore or process exception
                }
            });

答案 1 :(得分:1)

我有四个基本建议:

  1. 使用HttpClient代替过时的WebClientHttpClient可以本地处理异步操作,并且具有更大的灵活性可以利用。您甚至可以将下载的内容读取到不同线程上的字符串/流,因为您可以配置await不安排回操作。或者甚至将HttpClientHandler编程为在6秒后中断,如果超出则提高TaskCanceledException
  2. 避免吞咽异常(就像你在F函数中所做的那样),因为它会破坏调试并混淆问题的真正原因。在正常操作期间,正确编写的程序永远不会引发异常。
  3. 你正在以无用的方式使用线程,它们甚至没有重叠;他们只是等待彼此开始,因为你在每个线程开始后锁定了调用循环。在.NET中,最好使用Task进行多任务处理(例如,将其称为Task.Run(async delegate() { await yourTask(); })(或AsyncContext.Run(...),如果您需要UI访问权限)并且它不会获胜阻止任何事情。
  4. 整个GetInformationFromWeb类目前毫无意义 - 而且您也毫无意义地生成多个客户端对象,因为一个HTTP客户端对象可以处理多个请求(如果您使用HttpClient甚至没有额外的膨胀 - 您只需将其实例化为具有所有必要配置的静态全局变量,然后使用与client.GetStringAsync(Uri uri)一样少的代码从任何地方调用它。
  5. OT:这是某种学术项目吗?