2013-03-03 8 views
7

Хорошо, здесь мой вопрос. Я хочу начать потоки до определенного числа. Допустим, 100. Таким образом, он начнет запускать потоки и постоянно проверяет количество запущенных потоков. Когда достигнуто максимальное число, оно прекратит запуск новых потоков. Но с правильным интервалом проверки или завершенной нитью будет сигнал, и он начнет новую нить.Как сделать определенное количество потоков, работающих все время

Таким образом, у меня всегда будет определенное количество работающих потоков.

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

Но мое решение не подходит мне надлежащим образом. Полагаю, было бы лучше, если бы заполненный поток прозвучал, и тогда контролер начнет новый, если мы ниже максимального количества порогов потоков.

Я видел много примеров threadpool, но большинство из них не содержит пулов в очереди с максимальным количеством работающих потоков. Я имею в виду, что они просто продолжают создавать темы, пока они не закончатся. Но скажем, у меня есть 500k URL-адресов для сбора урожая. Я не могу просто запустить их все в цикле for с пулом потоков.

платформа C# 4.5 WPF приложение

А вот ниже мое решение. На самом деле я ищу лучшего. Не улучшилось это.

private void Button_Click_4(object sender, RoutedEventArgs e) 
{ 
    Task.Factory.StartNew(() => 
    { 
     startCrawler(); 
    }); 
} 

void startCrawler() 
{ 
    int irMaximumThreadcount = 100; 
    List<Task> lstStartedThreads = new List<Task>(); 
    while (true) 
    { 
     for (int i = 0; i < lstStartedThreads.Count; i++) 
     { 
      if (lstStartedThreads[i].IsCompleted == true) 
      { 
       lstStartedThreads[i].Dispose(); 
       lstStartedThreads.RemoveAt(i); 
      } 
     } 

     if (lstStartedThreads.Count < irMaximumThreadcount) 
     { 
      var vrTask = Task.Factory.StartNew(() => 
      { 
       func_myTask(); 
      }); 
      lstStartedThreads.Add(vrTask); 
     } 

     System.Threading.Thread.Sleep(50); 
    } 
} 

void func_myTask() 
{ 

} 
+0

«Я не могу просто запустить все из них в цикле for с пулом потоков». - Ты действительно пробовал? Запуск нескольких потоков с предположением, что это сделает ваше общее интернет-соединение быстрее, не звучит «как правильный способ». Также conisder с использованием асинхронных операций - не потребуется столько потоков ... Если у вас нет чего-то вроде 32-ядерной машины ... –

ответ

6

Лично я хотел бы использовать PLINQ для этого, и в частности, WithDegreeOfParallelism метод, который ограничивает количество одновременных казней до переданному в стоимости.

private IEnumerable<Action> InfiniteFunctions() 
{ 
    while(true) 
    { 
     yield return func_myTask; 
    } 
} 

private void Button_Click_4(object sender, RoutedEventArgs e) 
{ 
    int irMaximumThreadcount = 100; 
    InfiniteFunctions() 
     .AsParallel() 
     .WithDegreeOfParallelism(irMaximumThreadcount) 
     .ForAll(f => f()); 
} 

EDIT: На самом деле чтение документации, кажется, что irMaximumThreadCount может быть только максимум из 64, так что следите за этим.

EDIT 2: Хорошо, было лучше смотреть и кажется Parallel.ForEach принимает параметр ParallelOptions, который включает в себя MaxDegreeOfParallelism свойство, которое не ограничивается - Check it out. Таким образом, ваш код может быть таким:

private void CrawlWebsite(string url) 
{ 
    //Implementation here 
} 

private void Button_Click_4(object sender, RoutedEventArgs e) 
{ 
    var options = new ParallelOptions() 
    { 
     MaxDegreeOfParallelism = 2000 
    }; 

    Parallel.ForEach(massiveListOfUrls, options, CrawlWebsite); 
} 
+0

теперь это интересно. поэтому вы говорите, что этот метод можно использовать, например, для сканирования страниц на 500 тыс. страниц. позвольте мне попробовать :) – MonsterMMORPG

+0

ой. то это бесполезно для меня :) Я начинаю 2000 потоков, чтобы проверить живые прокси, например ^^, хотя диспетчер задач показывает 490 потоков. я не знаю, почему не 2000 :) – MonsterMMORPG

+0

Ах, следите за моим редактированием - max всего 64 параллельно. И да, вы могли бы перебрать свой список из 500 000 элементов и выполнить func для каждого элемента. – Felix

0

Неточный ответ, но я думаю, что это поможет вам в правильном направлении.

Во-первых, посмотрите на Thread.Join, особенно простой пример, приведенный в нижней части этой страницы. Этот подход превосходит Thread.Sleep() и более подходит для вашей цели. Я думаю о линиях * Присоединиться * Ввод «менеджера» вместо * Sleep * ing.

Второй вариант, который может или не подходит вашей цели, - это новая библиотека Tasks. Поскольку вы используете последнюю версию фреймворка, этот параметр доступен, но я думаю, вы не можете контролировать фактическое количество потоков, созданных в библиотеке задач. Он автоматически выбирает это значение на основе основного планировщика. Тем не менее, есть опция с именем ParallelOptions.MaxDegreeOfParallelism, которая звучит интересно.

+0

, насколько я знаю, соединение потоков используется для ожидания завершения всех задач. я неверен? если да, то как я могу его использовать? Мне не нужно ждать всех задач. когда 1 задача закончена, другая начнется немедленно, так что всегда будет выполняться определенное количество задач – MonsterMMORPG

+0

мммм ... Не уверен в этом 100%, но я думаю, что Join только останавливает вызывающий поток.Другая идея может состоять в том, чтобы присоединиться к вновь созданным рабочим потокам, чтобы они сразу начали работать, как только один из текущих запущенных потоков сигнализирует, что он завершен, поэтому менеджер не должен снова и снова проверять. – dotNET

+0

Нет, это не сработает. потому что потоки незавершенны. первый запуск может завершиться последним или последним начатым, может завершиться первым. – MonsterMMORPG

1

.NET 4.0 представил несколько коллекций со встроенным управлением параллелизмом, которые должны быть идеальными для этой ситуации. Сбор блокировки будет более эффективным, чем спящий цикл while. Затем вы просто создаете x потоков, которые читаются из очереди блокировки.

BlockingCollection<string> queue = new BlockingCollection<string>(listOfUrls); 

for (int x=0; x < MaxThreads; x++) 
{ 
    Task.Factory.StartNew(() => 
    { 
     while (true) 
     { 
      string url = queue.Take(); // blocks until url is available 
      // process url; 
     } 
    }, TaskCreationOptions.LongRunning); 
} 

Вы отмечаете задачу как долгое время, поэтому она создаст собственную нить вместо использования пула потоков. Если вам нужно сначала сначала, вы можете передать ConcurrentQueue<T> в конструктор блокирующей коллекции. http://msdn.microsoft.com/en-us/library/dd287085.aspx

3

Вы смешиваете задачи с потоками. Задача - это не поток. There is no guarantee that each task will have it's own thread.

На самом деле TPL (Task Parallel Library) - это своего рода очередь. Это означает, что вы можете просто создавать и запускать задачи для каждого объекта Func или Action. There is no easy way to control the number of threads, которые фактически созданы.

Однако вы можете создавать множество задач с небольшими накладными расходами, поскольку TPL вставляет их в очередь и применяет дополнительную логику, чтобы сбалансировать работу над потоками thread pool.

Если некоторые задачи должны выполняться один за другим, вы можете использовать Task.ContinueWith, чтобы их поставить в очередь. Также можно начинать новые задания с Task.Factory.ContinueWhenAny или Task.Factory.ContinueWhenAll.

Это также ключ к тому, как вы можете контролировать количество параллельных задач, которые вы хотите создать: просто создайте необходимое количество задач и оставьте оставшиеся задания с помощью ContinueWhenAny. Каждый раз, когда задача заканчивается, будет запущена следующая.

Опять же: TPL будет балансировать работу между потоками в пуле потоков. В любом случае вам необходимо учитывать использование других ресурсов, таких как дисковый ввод-вывод или подключение к Интернету. Наличие большого количества задач, которые пытаются использовать одни и те же ресурсы одновременно, может значительно замедлить работу вашей программы.

+0

У меня много ресурсов. 850 МБ в секунду скорость чтения чтения/записи, 50-мегабитное оптоволоконное соединение. Во всяком случае, это полезная информация для голосования. :) – MonsterMMORPG

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