2016-08-28 2 views
0

У меня есть программа, которая получает код для ~ 500 веб-страниц через каждые 5 минутПолучение 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; 
    } 
} 
+0

Какое исключение возвращено? – Legends

+0

@Legends существует много «исключения прерывания потока» на выходе – mojtaba357

+0

, вы можете использовать 'Continue' в вашем блоке catch, обратитесь по этой ссылке: http://stackoverflow.com/questions/654113/how-do-i-skip-an -iteration-оф-а-Еогеасп-петля –

ответ

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. Использование HttpClient вместо устаревшего WebClient. HttpClient может обрабатывать асинхронные операции изначально и имеет гораздо большую гибкость, чтобы воспользоваться преимуществами. Вы даже можете прочитать загруженное содержимое в строки/потоки в другом потоке, так как вы можете настроить 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).

OT: Это какой-то академический проект?

Смежные вопросы