【问题标题】:Getting HTML response fails respectively after first fail第一次失败后分别获取 HTML 响应失败
【发布时间】:2017-01-04 13:33:40
【问题描述】:

我有一个程序每 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;
        }
    }
}

和网络客户端类

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;
    }
}

【问题讨论】:

标签: c# .net httpwebrequest webrequest httpwebresponse


【解决方案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
                }
            });

【讨论】:

    【解决方案2】:

    我有四个基本建议:

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

    OT:这是某种学术项目吗?

    【讨论】:

      猜你喜欢
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-31
      • 2023-01-25
      • 2011-05-21
      • 1970-01-01
      相关资源
      最近更新 更多