2010-10-14 3 views
22

Я только что просмотрел действительно ужасный код - код, который отправляет сообщения на последовательный порт, создавая новый поток для упаковки и сборки сообщения в новом потоке для каждого отправленного сообщения. Да, для каждого сообщения создается pthread, бит правильно настроен, тогда поток завершается. Я не знаю, почему кто-то будет делать такие вещи, но возникает вопрос: насколько накладные расходы возникают при создании потока?Сколько накладных расходов возникает при создании потока?

+0

Какая реализация pthread? –

+0

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

+0

Я хотел бы прокомментировать, что да, это, наверное, ужасная вещь, которая приводит к моему вопросу, сколько накладных расходов возникает при создании потока (в общем) Честно говоря, я не знаю, как определить или даже измерьте реализацию библиотеки pthread – jdt141

ответ

6

... посылает сообщения на последовательный порт ... для каждого сообщения нитей создается, биты настроены правильно, то поток завершается. ... сколько накладных расходов при создании потока?

Это очень специфичный для системы. Например, в прошлый раз, когда я использовал потоки VMS, кошмарно медленно (это были годы, но из памяти один поток мог создавать что-то вроде 10 больше в секунду (и если бы вы сохраняли это на несколько секунд без потоков, выходящих из вас, ядро)), тогда как в Linux вы, вероятно, можете создавать тысячи. Если вы хотите точно знать, сравните его с вашей системой. Но это не очень полезно, просто зная, что, не зная больше о сообщениях: независимо от того, являются ли они в среднем 5 байтов или 100 тыс., Независимо от того, отправлены они смежно или простаивает линия между ними, и каковы требования к латентности для приложения, к правильности использования потока кода в качестве абсолютного измерения затрат на создание потоков. И производительность, возможно, не должна была доминировать в дизайне.

7

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

+3

Согласен. Зачем беспокоиться о микросекундах задержки от создания потока, когда сетевое взаимодействие, вероятно, вызывает задержки в десятки миллисекунд или даже секунды. – JSON

8

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

http://www.personal.kent.edu/~rmuhamma/OpSystems/Myos/threads.htm

Тема дешевы в том смысле, что

  1. Они нужны только стеки и хранение регистров поэтому потоки дешевы создать.

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

  3. Контекстное переключение происходит быстро при работе с потоками. Причиной является , что нам нужно сохранить и/или восстановить ПК, SP и регистры.

Более того же here.

Operating System Concepts 8th Edition В (стр 155) авторы пишут о преимуществах резьбе:

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

+4

Но альтернативой, вероятно, является один повторный поток или пул потоков, а не процесс. –

+0

@Matthew Flaschen Я имел в виду альтернативу созданию любого потока, а не альтернативу созданию потока (нитей) в способе, которым задает вопрос :) – ubiquibacon

+1

На самом деле процесс создания дешевле, чем создание потоков. Компонент вилки создания процессов в основном не стоит, поскольку страницы памяти дублируются на аппаратном уровне. Посмотрите, что нашел команда google chrome: http://www.hanselman.com/blog/MicrosoftIE8AndGoogleChromeProcessesAreTheNewThreads.aspx –

10

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

С точки зрения накладных расходов, создание/разрушение резьбы, особенно на Windows, довольно дорого. Где-то порядка десятков микросекунд, чтобы быть конкретным. Он должен, по большей части, выполняться только в начале и конце приложения, за исключением, возможно, динамически измененных пулов потоков.

+2

Да, «вечный» посвященный рабочий поток также решает возможные проблемы с МТ. – ruslik

+0

@MichaelGoldshteyn: у вас есть идея, как это сделать [в python] (http://stackoverflow.com/q/33453581/2284570)? – user2284570

2

Создание темы и вычисление в потоке довольно дорого. Необходимо настроить все данные strucutres, поток, зарегистрированный в ядре, и переключатель потока должен произойти так, чтобы новый поток фактически выполнялся (в неуказанном и непредсказуемом времени). Выполнение thread.start не означает, что главная функция потока вызывается немедленно. Поскольку статья (упомянутая typoking) указывает, что создание потока дешево только по сравнению с созданием процесса. В целом, это довольно дорого.

Я никогда бы не использовать нить

  • для короткого вычисления
  • вычисления, где мне нужен результат в моем потоке кода (что значит, я начинаю нить и ждать для него чтобы вернуть результат это вычисление

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

НТН

Марио

+0

downvoters позаботиться объяснить? –

+0

Недостатки озадачивают. Понимание стоимости коммутаторов контекста является ключевым для любого обсуждения затрат на потоки. –

2

При любой разумной реализации стоимость создания потоков должна быть пропорциональна количеству входящих в нее системных вызовов и на том же уровне, что и обычные системные вызовы, такие как open и read. Некоторые случайные измерения в моей системе показали, что pthread_create занимает примерно в два раза больше времени, чем open("/dev/null", O_RDWR), что очень дорого по сравнению с чистыми вычислениями, но очень дешево относительно любых операций ввода-вывода или других операций, которые связаны с переключением между пространством пользователя и ядра.

+0

В моем случае это будет связано с созданием тысяч потоков. Есть ли способ [избегать этого в python] (http://stackoverflow.com/q/33453581/2284570)? – user2284570

3

Для сравнения, посмотрим на OSX: Link

  • ядра структуры данных: Приблизительно 1 КБ Стек площадь: 512 КБ (вторичные потоки): 8 МБ (OS X, основной поток), 1 МБ (IOS основная нить )

  • время создания: около 90 микросекунд

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

22

Чтобы воскресить эту старую нить, я только что сделал простой код тест:

#include <thread> 

int main(int argc, char** argv) 
{ 
    for (volatile int i = 0; i < 500000; i++) 
    std::thread([](){}).detach(); 
    return 0; 
} 

Я скомпилировал его g++ test.cpp -std=c++11 -lpthread -O3 -o test. Затем я запускал его три раза подряд на старом (ядро 2.6.18), сильно загруженном (выполняющем восстановление базы данных) медленном ноутбуке (Intel Core i5-2540M). Результаты трех последовательных прогонов: 5.647s, 5.515s и 5.561s. Таким образом, мы рассматриваем чуть более 10 микросекунд на поток на этой машине, возможно, гораздо меньше на вашем.

Это не так много накладных расходов, учитывая, что последовательные порты max превышают около 1 бит за 10 микросекунд. Теперь, конечно, есть различные дополнительные потери потоков, которые можно получить с участием переданных/захваченных аргументов (хотя вызовы функций могут накладывать некоторые), замедления кэша между ядрами (если несколько потоков на разных ядрах сражаются по одной и той же памяти одновременно) и т. д. Но в целом я очень сомневаюсь, что прецедент, который вы представили, будет отрицательно влиять на производительность вообще (и может обеспечить выгоды, в зависимости), несмотря на то, что вы уже предварительно упреждали обозначение понятия «действительно ужасный код», даже не зная, сколько времени потребуется запустите поток.

Независимо от того, хорошо ли это или нет, многое зависит от деталей вашей ситуации. На что еще ответственен вызывающий поток? Что конкретно связано с подготовкой и записью пакетов? Как часто они выписываются (с каким распределением? Равномерным, сгруппированным и т. Д.?) И какова их структура? Сколько ядер имеет система? И т. Д. В зависимости от деталей оптимальное решение может быть от «нитей» вообще до «общего пула потоков» до «потока для каждого пакета».

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

0

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

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

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

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