Я пишу сервер и отправляю каждое действие в отдельный поток при получении запроса. Я делаю это потому, что почти каждый запрос делает запрос к базе данных. Я использую библиотеку потоков, чтобы сократить строительство / уничтожение потоков.
Мой вопрос: какова хорошая точка отсечения для потоков ввода-вывода, подобных этим? Я знаю, что это будет приблизительная оценка, но мы говорим сотни? Тысячи?
Как бы я понял, что это за отсечка?
РЕДАКТИРОВАТЬ:
Спасибо всем за ваши ответы, похоже, мне просто нужно проверить это, чтобы узнать мой потолок подсчета потоков. Вопрос в том, откуда мне знать, что я достиг этого потолка? Что именно я должен измерить?
Ответы:
Некоторые люди скажут, что двух нитей слишком много - я не совсем в этом лагере :-)
Вот мой совет: измерить, не угадать. Одно из предложений заключается в том, чтобы сделать его настраиваемым и сначала установить его на 100, а затем выпустить программное обеспечение на волю и отслеживать, что происходит.
Если использование потоков достигает 3, то 100 - это слишком много. Если он остается на уровне 100 в течение большей части дня, увеличьте его до 200 и посмотрите, что произойдет.
Вы могли бы фактически заставить свой код контролировать использование и корректировать конфигурацию для следующего запуска, но это, вероятно, излишне.
Для уточнения и уточнения:
Я не сторонник создания собственной подсистемы пула потоков, во что бы то ни стало, используйте ту, которая у вас есть. Но, поскольку вы спрашивали о хорошей точке отсечения для потоков, я предполагаю, что ваша реализация пула потоков способна ограничить максимальное количество создаваемых потоков (что хорошо).
Я написал код пула потоков и соединений с базой данных, и у них есть следующие функции (которые я считаю важными для производительности):
Первый устанавливает базовую линию для минимальной производительности с точки зрения клиента пула потоков (это количество потоков всегда доступно для использования). Второй устанавливает ограничение на использование ресурсов активными потоками. Третий возвращает вас к базовой линии в спокойное время, чтобы минимизировать использование ресурсов.
Вам необходимо сбалансировать использование ресурсов с наличием неиспользуемых потоков (A) и использованием ресурсов с отсутствием достаточного количества потоков для выполнения работы (B).
(A) - это, как правило, использование памяти (стеки и т. Д.), Поскольку поток, не выполняющий работу, не будет использовать большую часть ЦП. (B) обычно будет задержкой в обработке запросов по мере их поступления, так как вам нужно ждать, пока поток станет доступным.
Вот почему вы измеряете. Как вы заявляете, подавляющее большинство ваших потоков будет ожидать ответа от базы данных, поэтому они не будут работать. Есть два фактора, которые влияют на количество потоков, которые вы должны учитывать.
Первый - это количество доступных подключений к БД. Это может быть жестким пределом, если вы не можете увеличить его в СУБД - я собираюсь предположить, что ваша СУБД может принимать неограниченное количество соединений в этом случае (хотя в идеале вы должны также измерять это).
Затем количество потоков, которые вы должны иметь, зависит от вашего исторического использования. Минимум, который вы должны запустить, - это минимальное число, которое вы когда-либо использовали, + A%, с абсолютным минимумом (например, и сделать его настраиваемым так же, как A) 5.
Максимальное количество потоков должно быть вашим историческим максимумом + B%.
Вы также должны следить за изменениями поведения. Если по какой-то причине ваше использование переходит к 100% доступности в течение значительного времени (чтобы это могло повлиять на производительность клиентов), вам следует увеличить максимально допустимое значение, пока оно снова не увеличится на B%.
В ответ на «что именно я должен измерить?» вопрос:
Что вы должны конкретно измерить, так это максимальное количество потоков при одновременном использовании (например, ожидание возврата из вызова БД) под нагрузкой. Затем добавить коэффициент запаса прочности на 10% , например (выделено, так как другие плакаты , кажется, принять мои примеры как основные рекомендации).
Кроме того, это следует делать в производственной среде для тюнинга. Это хорошо, чтобы получить оценку заранее, но вы никогда не знаете, какой продукт будет иметь значение (именно поэтому все эти вещи должны быть настраиваемыми во время выполнения). Это для того, чтобы поймать ситуацию, такую как неожиданное удвоение входящих вызовов клиента.
источник
Этот вопрос обсуждался довольно тщательно, и у меня не было возможности прочитать все ответы. Но вот несколько вещей, которые следует учитывать при рассмотрении верхнего предела числа одновременных потоков, которые могут мирно сосуществовать в данной системе.
Теперь вы можете настроить размер своего стека для включения большего количества потоков, но тогда вам придется учитывать издержки управления потоками (создание / уничтожение и планирование). Вы можете принудительно установить привязку ЦП к данному процессу, а также к определенному потоку, чтобы связать их с конкретными ЦП, чтобы избежать накладных расходов на миграцию потоков между ЦП и избежать проблем с холодными деньгами.
Обратите внимание, что можно создавать тысячи потоков по своему желанию, но когда в Linux заканчивается виртуальная машина, он просто случайным образом начинает уничтожать процессы (то есть потоки). Это сделано для того, чтобы профиль утилит не был максимально увеличен. (Функция полезности сообщает о общесистемной полезности для заданного количества ресурсов. При постоянных ресурсах в этом случае циклы ЦП и память, кривая полезности сглаживается со все большим количеством задач).
Я уверен, что планировщик ядра Windows также делает что-то подобное, чтобы справиться с чрезмерным использованием ресурсов
[1] http://adywicaksono.wordpress.com/2007/07/10/i-can-not-create-more-than-255-threads-on-linux-what-is-the-solutions/
источник
Если ваши потоки выполняют какую-либо ресурсоемкую работу (ЦП / Диск), вы редко увидите преимущества, превышающие один или два, и слишком большое их количество очень быстро снизит производительность.
В лучшем случае ваши последующие потоки будут остановлены, пока завершатся первые, или у некоторых будут блоки с низким объемом служебной информации в ресурсах с низким уровнем конкуренции. В худшем случае вы начинаете перегружать кеш / диск / сеть, и ваша общая пропускная способность падает до минимума.
Хорошим решением является размещение запросов в пуле, которые затем отправляются рабочим потокам из пула потоков (и да, избегание непрерывного создания / уничтожения потоков - отличный первый шаг).
Число активных потоков в этом пуле можно затем настроить и масштабировать на основе результатов вашего профилирования, оборудования, на котором вы работаете, и других вещей, которые могут происходить на машине.
источник
Следует помнить одну вещь: Python (по крайней мере, версия на основе C) использует так называемую глобальную блокировку интерпретатора, которая может оказать огромное влияние на производительность на многоядерных машинах.
Если вам действительно нужно максимально использовать многопоточный Python, вы можете рассмотреть возможность использования Jython или чего-то еще.
источник
Как правильно сказал Пакс, измеряй, не угадывай . То, что я сделал для DNSwitness, и результаты были удивительными: идеальное количество потоков было намного выше, чем я думал, что-то вроде 15 000 потоков, чтобы получить самые быстрые результаты.
Конечно, это зависит от многих вещей, поэтому вы должны измерить себя.
Полные меры (только на французском языке) в Combien de fils d'exécution? ,
источник
Я написал несколько многопоточных приложений. Обычно я допускаю, чтобы число потенциальных потоков указывалось в файле конфигурации. Когда я настроился на конкретных клиентов, я установил достаточно высокое число, чтобы загрузка всех ядер ЦП была довольно высокой, но не настолько высокой, чтобы я столкнулся с проблемами с памятью (это были 32-разрядные операционные системы в время).
Иными словами, если вы достигнете некоторого узкого места, будь то ЦП, пропускная способность базы данных, пропускная способность диска и т. Д., Добавление большего количества потоков не увеличит общую производительность. Но пока вы не достигли этой точки, добавьте больше тем!
Обратите внимание, что это предполагает, что рассматриваемые системы предназначены для вашего приложения, и вам не нужно красиво играть (избегать голодания) других приложений.
источник
Ответ «большого железа» - это, как правило, один поток на ограниченный ресурс - процессор (с привязкой к ЦП), постановка на охрану (с привязкой к вводу / выводу) и т. Д. - но это работает только в том случае, если вы можете направить работу в правильный поток для ресурса в быть доступным.
Там, где это невозможно, учтите, что у вас есть грибные ресурсы (ЦП) и не-грибные ресурсы (оружие). Для процессоров не критично назначать каждый поток определенному процессору (хотя это помогает в управлении кэшем), но для рук, если вы не можете назначить поток для руки, вы попадаете в теорию очередей и какое оптимальное число для хранения рук занятый. Обычно я думаю, что если вы не можете направить запросы на основе используемой руки, то иметь 2-3 потока на руку будет правильным.
Сложность возникает, когда единица работы, передаваемая потоку, не выполняет достаточно атомарную единицу работы. Например, вы можете иметь поток в одной точке доступа к диску, а в другой точке ждать в сети. Это увеличивает количество «взломов», когда дополнительные потоки могут войти и выполнять полезную работу, но также увеличивает возможность для дополнительных потоков загрязнять кеши друг друга и т. Д. И перегружать систему.
Конечно, вы должны взвесить все это против «веса» нити. К сожалению, большинство систем имеют очень тяжелые потоки (а то, что они называют «легкими потоками», часто вовсе не являются потоками), поэтому лучше ошибаться на низкой стороне.
Что я видел на практике, так это то, что очень тонкие различия могут иметь огромное значение в том, сколько потоков оптимально. В частности, проблемы с кешем и конфликты блокировок могут сильно ограничить практический параллелизм.
источник
Следует учитывать, сколько ядер существует на компьютере, на котором будет выполняться код. Это представляет собой жесткое ограничение на количество потоков, которые могут выполняться в любой момент времени. Однако, если, как и в вашем случае, ожидается, что потоки будут часто ожидать, пока база данных выполнит запрос, вы, вероятно, захотите настроить свои потоки в зависимости от того, сколько одновременных запросов может обработать база данных.
источник
Я думаю, что это немного уловка для вашего вопроса, но почему бы не разделить их на процессы? В моем понимании работы в сети (с туманных дней прошлого я вообще не кодирую сети) было то, что каждое входящее соединение может обрабатываться как отдельный процесс, потому что тогда, если кто-то делает что-то неприятное в вашем процессе, это не уничтожить всю программу.
источник
ryeguy, в настоящее время я занимаюсь разработкой подобного приложения, и мой номер потока установлен на 15. К сожалению, если я увеличу его до 20, он вылетает. Так что, да, я думаю, что лучший способ справиться с этим - это определить, позволяет ли ваша текущая конфигурация больше или меньше числа потоков.
источник
В большинстве случаев вы должны позволить пулу потоков обрабатывать это. Если вы разместите некоторый код или предоставите более подробную информацию, может быть легче увидеть, если по какой-то причине поведение пула потоков по умолчанию будет не лучшим.
Вы можете найти больше информации о том, как это должно работать здесь: http://en.wikipedia.org/wiki/Thread_pool_pattern
источник
Столько потоков, сколько ядер ЦП - это то, что я слышал очень часто.
источник