Подтвердить что ты не робот

Сколько накладных расходов возникает при создании потока?

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

#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 микросекунд. Теперь, конечно, существуют различные дополнительные потери потоков, которые можно получить вовлекаемыми переданными/захваченными аргументами (хотя вызовы функций могут накладывать некоторые), замедления кэша между ядрами (если несколько потоков на разных ядрах сражаются по одной и той же памяти одновременно) и т.д. Но в целом я очень сомневаюсь, что прецедент, который вы представили, будет отрицательно влиять на производительность вообще (и может обеспечить выгоды, в зависимости), несмотря на то, что вы уже предварительно упреждали обозначение понятия "действительно ужасный код", даже не зная, сколько времени потребуется запустите поток.

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

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

Ответ 3

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

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

Ответ 4

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

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

Нитки дешевы в том смысле, что

  • Им нужен только стек и хранилище для регистров , поэтому потоки дешевы для создания.

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

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

Больше того же здесь.

В "Концепции операционной системы 8-е издание" (стр. 155) авторы пишут о преимуществах потоковой передачи:

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

Ответ 5

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

Ответ 6

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

  • Структуры данных ядра: Примерно 1 КБ Размер стека: 512 КБ (вторичные потоки): 8 МБ (основной поток ОС X), 1 МБ (основная часть iOS поток)

  • Время создания: приблизительно 90 микросекунд

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

Ответ 7

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

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

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

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

HTH

Марио

Ответ 8

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

Ответ 9

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

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

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