2015-05-11 5 views
5

Я пытаюсь создать приложение, которое многопоточно загружает изображения с веб-сайта, в качестве введения в потоки. (никогда не использовалась резьба должным образом)Где эти 1k темы из

Но в настоящее время создается 1000+ потоков, и я не уверен, откуда они.

я первый в очереди поток в пул потоков, для начала я только 1 работа в массиве заданий

foreach (Job j in Jobs) 
{ 
    ThreadPool.QueueUserWorkItem(Download, j); 
} 

Который начинает пустоту Download(object obj) в новом потоке, где петли через определенное количество страниц (изображения требуется/42 изображений на странице)

for (var i = 0; i < pages; i++) 
{ 
    var downloadLink = new System.Uri("http://www." + j.Provider.ToString() + "/index.php?page=post&s=list&tags=" + j.Tags + "&pid=" + i * 42); 

    using (var wc = new WebClient()) 
    { 
     try 
     { 
      wc.DownloadStringAsync(downloadLink); 
      wc.DownloadStringCompleted += (sender, e) => 
      { 
       response = e.Result; 
       ProcessPage(response, false, j); 
      }; 
     } 
     catch (System.Exception e) 
     { 
      // Unity editor equivalent of console.writeline 
      Debug.Log(e); 
     } 
    } 
} 

поправьте меня, если я не прав, то следующий пустота вызывается в том же потоке

void ProcessPage(string response, bool secondPass, Job j) 
{ 
    var wc = new WebClient(); 
    LinkItem[] linkResponse = LinkFinder.Find(response).ToArray(); 

    foreach (LinkItem i in linkResponse) 
    { 
     if (secondPass) 
     { 
      if (string.IsNullOrEmpty(i.Href)) 
       continue; 
      else if (i.Href.Contains("http://loreipsum.")) 
      { 
       if (DownloadImage(i.Href, ID(i.Href))) 
        j.Downloaded++; 
      } 
     } 
     else 
     { 
      if (i.Href.Contains(";id=")) 
      { 
       var alterResponse = wc.DownloadString("http://www." + j.Provider.ToString() + "/index.php?page=post&s=view&id=" + ID(i.Href)); 
       ProcessPage(alterResponse, true, j); 
      } 
     } 
    } 
} 

И, наконец, переходит к последней функции и загружает реальное изображение

bool DownloadImage(string target, int id) 
{ 
    var url = new System.Uri(target); 
    var fi = new System.IO.FileInfo(url.AbsolutePath); 
    var ext = fi.Extension; 

    if (!string.IsNullOrEmpty(ext)) 
    { 
     using (var wc = new WebClient()) 
     { 
      try 
      { 
       wc.DownloadFileAsync(url, id + ext); 
       return true; 
      } 
      catch(System.Exception e) 
      { 
       if (DEBUG) Debug.Log(e); 
      } 
     } 
    } 
    else 
    { 
     Debug.Log("Returned Without a extension: " + url + " || " + fi.FullName); 
     return false; 
    } 
    return true; 
} 

Я не знаю, как я начинаю это много потоков, но хотелось бы знать.

Редактировать

Цели этой программы заключается, чтобы загрузить другую работу на рабочих местах, в то же время (не более 5) каждый скачивают максимум 42 изображений в то время.

поэтому максимум/максимум изображений можно загрузить максимум в любое время.

+4

Вы запускаете операцию async внутри другого потока. почему бы просто не использовать async, и это так. ? какие преимущества дает вам резьба, в данном случае? – Tigran

+0

@ Тигран. Наверное, нет, просто пытаясь получить зависание, было бы разумнее использовать блокирующий вызов вместо асинхронного вызова, а затем в ситуации с потоками? –

+2

Если вы используете async, не используйте threading. используйте потоки, если вы собираетесь контролировать рабочую нагрузку на параллелизм, поэтому используйте столько потоков, сколько требуется, и не более. – Tigran

ответ

2

Прежде всего, как вы измерили количество потоков? Почему вы думаете, что у вас есть тысяча из них в вашей заявке? Вы используете ThreadPool, поэтому вы не создаете их самостоятельно, и ThreadPool не создадут такого большого количества их для своих нужд.

Во-вторых, вы смешиваете синхронные и асинхронные операции в своем коде. Поскольку вы не можете использовать TPL и async/await, давайте рассмотрим ваш код и посчитаем созданный вами unit-of-works, чтобы вы могли свести их к минимуму. После этого количество поставленных в очередь предметов в ThreadPool уменьшится, и ваше приложение получит необходимую производительность.

  1. Вы не установите метод SetMaxThreads в вашем приложении, поэтому, according the MSDN:

    Максимальное количество темы пула потоков
    Количество операций, которые могут быть поставлены в очередь на поток пул ограничен только доступной памятью; Однако пул потоков ограничивает количество потоков, которые могут быть активны в процессе одновременно.По умолчанию ограничение составляет 25 рабочих потоков на процессор и 1000 потоков ввода-вывода.

    Таким образом, вы должны установить максимум на 5.

  2. Я не могу найти место в вашем коде, где вы проверяете 42 изображений на одно задание, вы увеличиваете значение только в ProcessPage методе.

  3. Проверьте ManagedThreadId на ручку WebClient.DownloadStringCompleted. Выполняется ли она в разных направлениях или нет.
  4. Вы добавляете новый элемент в очередь ThreadPool, почему вы используете асинхронную операцию для загрузки? Используйте synchronious overload, например:

    ProcessPage(wc.DownloadString(downloadLink), false, j); 
    

    Это не создаст еще один пункт в ThreadPool очереди, и вы не имели бы переключение контекста sinchronisation здесь.

  5. В переменной wc ваша сборка не является сборкой мусора, поэтому вы не освобождаете все свои ресурсы здесь. Добавить using заявление здесь:

    void ProcessPage(string response, bool secondPass, Job j) 
    { 
        using (var wc = new WebClient()) 
        { 
         LinkItem[] linkResponse = LinkFinder.Find(response).ToArray(); 
    
         foreach (LinkItem i in linkResponse) 
         { 
          if (secondPass) 
          { 
           if (string.IsNullOrEmpty(i.Href)) 
            continue; 
           else if (i.Href.Contains("http://loreipsum.")) 
           { 
            if (DownloadImage(i.Href, ID(i.Href))) 
             j.Downloaded++; 
           } 
          } 
          else 
          { 
           if (i.Href.Contains(";id=")) 
           { 
            var alterResponse = wc.DownloadString("http://www." + j.Provider.ToString() + "/index.php?page=post&s=view&id=" + ID(i.Href)); 
            ProcessPage(alterResponse, true, j); 
           } 
          } 
         } 
        } 
    } 
    
  6. В DownloadImage метод можно также использовать asynchronious нагрузку. Это также добавляет элемент в ThreadPoll очереди, и я думаю, что вы можете избежать этого, и использовать synchronious overload тоже:

    wc.DownloadFile(url, id + ext); 
    return true; 
    

Таким образом, в целом, избегать контекстно-переключений и распоряжаться своими ресурсами правильно.

0

Ваш wc WebClinet выйдет из сферы действия и будет беспорядочно собранным мусором перед асинхронным обратным вызовом. Также во всех асинхронных вызовах вы должны разрешить немедленное возвращение и вернуть фактическую делегированную функцию. Поэтому ProcessPage должен быть в двух местах. Кроме того, j в исходном цикле может выйти из области действия в зависимости от того, где объявлен Download в исходном цикле.

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

  • Нет связанных вопросов^_^