Сколько потоков слишком много?

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

Мой вопрос в том, что - какая хорошая точка отсечки для потоков ввода-вывода, подобных этим? Я знаю, что это будет просто приблизительная оценка, но мы говорим о сотнях? тысячи?


EDIT:

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

Ответ 1

Некоторые люди скажут, что двух потоков слишком много - я не совсем в этом лагере: -)

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

Если ваше использование потоков достигает максимума в 3, то 100 слишком много. Если в течение большей части дня он остается на уровне 100, увеличьте его до 200 и посмотрите, что произойдет.

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


Для уточнения и уточнения:

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

Я написал код объединения пула потоков и базы данных, и у них есть следующие функции (которые, по моему мнению, необходимы для производительности):

  • минимальное количество активных потоков.
  • максимальное количество потоков.
  • выключение потоков, которые не использовались некоторое время.

Первый устанавливает базовую линию для минимальной производительности с точки зрения клиента пула потоков (это количество потоков всегда доступно для использования). Второй устанавливает ограничение на использование ресурсов активными потоками. Третий возвращает вас к базовой линии в спокойные времена, чтобы свести к минимуму использование ресурсов.

Вам необходимо сбалансировать использование ресурсов при использовании неиспользуемых потоков (A) для использования ресурсов, не имеющих достаточного количества потоков для выполнения работы (B).

(A) - это обычно использование памяти (стеки и т.д.), так как поток, не выполняющий работу, не будет использовать большую часть процессора. (B), как правило, является задержкой в ​​обработке запросов по мере их поступления, поскольку вам нужно ждать, пока поток станет доступным.

Вот почему вы измеряете. Как вы заявляете, подавляющее большинство ваших потоков будет ожидать ответа от базы данных, чтобы они не запускались. Есть два фактора, которые влияют на количество потоков, которые вы должны учитывать.

Первое - это количество доступных соединений DB. Это может быть жестким пределом, если вы не можете увеличить его в СУБД - я собираюсь предположить, что ваша СУБД может принимать неограниченное количество соединений в этом случае (хотя в идеале вы также должны это измерить).

Затем количество потоков, которые вы должны зависеть от вашего исторического использования. Минимальный минимум, который вы должны запустить, - это минимальное количество, которое у вас когда-либо имело + A%, с абсолютным минимумом (например, и сделать его настраиваемым точно так же, как A) 5.

Максимальное количество потоков должно быть вашим историческим максимумом + B%.

Вы также должны отслеживать изменения поведения. Если по какой-либо причине ваше использование будет доступно на 100% из доступных в течение значительного времени (так, чтобы это повлияло на производительность клиентов), вы должны увеличить максимальное допустимое значение до тех пор, пока оно снова не увеличится на B%.


В ответ на "что именно я должен измерить?" Вопрос:

То, что вы должны конкретно определить, - это максимальное количество потоков при одновременном использовании (например, ожидание возврата из вызова БД) под нагрузкой. Затем добавьте коэффициент безопасности 10% (подчеркнуто, поскольку другие плакаты, кажется, принимают мои примеры в качестве фиксированных рекомендаций).

Кроме того, это должно быть сделано в рабочей среде для настройки. Это нормально, чтобы получить предварительную оценку, но вы никогда не знаете, какая продукция будет бросать вам дорогу (вот почему все эти вещи должны настраиваться во время выполнения). Это должно поймать ситуацию, такую ​​как неожиданное удвоение входящих вызовов клиента.

Ответ 2

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

  • Размер стека в потоке: в Linux размер стека по умолчанию составляет 8 МБ (вы можете использовать ulimit -a, чтобы найти его).
  • Макс. виртуальная память, поддерживаемая данным вариантом ОС. Linux Kernel 2.4 поддерживает адресное пространство памяти 2 ГБ. с ядром 2.6, я немного больше (3 ГБ)
  • [1] показывает расчеты для максимального количества потоков при заданной максимальной поддержке VM. Для 2.4 получается около 255 потоков. для 2.6 число немного больше.
  • Какой у вас планировщик ядра kernel. Сравнивая планировщик ядра Linux 2.4 с 2.6, более поздний дает вам планирование O (1), не зависящее от количества задач, существующих в системе, в то время как первый из них больше O (n). Таким образом, возможности SMP в графике ядра также играют хорошую роль в максимальном количестве устойчивых потоков в системе.

Теперь вы можете настроить размер стека, чтобы включить больше потоков, но тогда вы должны учитывать накладные расходы на управление потоками (создание/уничтожение и планирование). Вы можете обеспечить привязку CPU к данному процессу, а также к определенному потоку, чтобы привязать их к конкретным процессорам, чтобы избежать накладных расходов на потоковую передачу между CPU и избежать проблем с холодным наливом.

Обратите внимание, что при его желании можно создавать тысячи потоков, но когда Linux заканчивается из VM, он просто случайно запускает процессы уничтожения (таким образом, потоки). Это означает, что профиль полезности не будет превышен. (Функция полезности сообщает об утилите всей системы для заданного количества ресурсов. При постоянном ресурсе в этом случае CPU Cycles and Memory кривая полезности выравнивается со все большим количеством задач).

Я уверен, что планировщик окон Windows также делает что-то подобное, чтобы справиться с чрезмерным использованием ресурсов

[1] http://adywicaksono.wordpress.com/2007/07/10/i-can-not-create-more-than-255-threads-on-linux-what-is-the-solutions/

Ответ 3

Если ваши потоки выполняют какую-либо ресурсоемкую работу (ЦП/Диск), вы редко увидите преимущества, превышающие один или два, и слишком многие быстро убьют производительность.

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

Хорошим решением является размещение запросов в пуле, которые затем отправляются в рабочие потоки из пула потоков (и да, избегая непрерывного создания/уничтожения потоков, является отличным первым шагом).

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

Ответ 4

Одна вещь, которую вы должны иметь в виду, - это то, что python (по крайней мере, версия на C) использует то, что называется глобальный блокиратор интерпретатора, который может иметь огромное влияние на производительность на многоядерных машинах.

Если вам действительно нужно больше всего на многопоточном питоне, вам может потребоваться использовать Jython или что-то еще.

Ответ 5

Как правильно сказал Pax, измерить, не угадайте. Это то, что я сделал для DNSwitness, и результаты были удивительными: идеальное количество потоков было намного выше, чем я думал, примерно 15 000 потоков получить самые быстрые результаты.

Конечно, это зависит от многих факторов, почему вы должны сами себя измерять.

Полные меры (только на французском языке) в Combien de fils d'exécution?.

Ответ 6

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

Ответ 7

Я написал несколько многопоточных приложений. Обычно я допускаю, чтобы количество потенциальных потоков определялось конфигурационным файлом. Когда я настроился на конкретных клиентов, я установил число, достаточно высокое, что мое использование всех ядер процессора было довольно высоким, но не настолько высоким, что я столкнулся с проблемами памяти (это были 32-разрядные операционные системы на время).

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

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

Ответ 8

Ответ на "большой железо" - это, как правило, один поток на ограниченный ресурс - процессор (привязка к ЦП), рука (привязка ввода/вывода) и т.д. - но это работает только в том случае, если вы можете перенаправить работу на нужную нить для доступ к ресурсу.

Если это невозможно, считайте, что у вас есть взаимозаменяемые ресурсы (ЦП) и неисправимые ресурсы (оружие). Для процессоров не критично назначать каждый поток конкретному процессору (хотя он помогает в управлении кешем), но для оружия, если вы не можете назначить нить в руку, вы попадаете в теорию массового обслуживания и какое оптимальное количество для хранения оружия занятый. Как правило, я думаю, что если вы не можете направлять запросы на основе используемой руки, то будет иметься 2-3 потока на руку.

Усложнение возникает, когда единица работы, переданная в поток, не выполняет разумно атомную единицу работы. Например, у вас может быть поток в одной точке доступа к диску, в другой точке ждут в сети. Это увеличивает количество "трещин", когда дополнительные потоки могут входить и выполнять полезную работу, но это также увеличивает возможность добавления дополнительных потоков для загрязнения друг друга в кешах и т.д., А также путаницу системы.

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

То, что я видел на практике, состоит в том, что очень тонкие различия могут иметь огромное значение в том, сколько потоков является оптимальным. В частности, проблемы с кешем и конфликты блокировок могут значительно ограничить количество практических concurrency.

Ответ 9

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

Ответ 10

ryeguy, в настоящее время я разрабатываю аналогичное приложение, а число моих потоков равно 15. К сожалению, если я увеличу его на 20, он сработает. Итак, да, я считаю, что лучший способ справиться с этим - измерить, разрешает ли ваша текущая конфигурация больше или меньше числа X потоков.

Ответ 11

В большинстве случаев вы должны разрешить пул потоков обрабатывать это. Если вы разместите какой-либо код или дадите более подробную информацию, может быть проще увидеть, есть ли причина, по которой поведение пула по умолчанию не будет оптимальным.

Вы можете найти дополнительную информацию о том, как это должно работать здесь: http://en.wikipedia.org/wiki/Thread_pool_pattern

Ответ 12

Так много потоков, как ядро ​​процессора, это то, что я слышал очень часто.