Недавно я слышал, как некоторые люди говорят, что в Linux почти всегда лучше использовать процессы вместо потоков, так как Linux очень эффективен в обработке процессов и потому, что с потоками связано очень много проблем (таких как блокировка). Тем не менее, я подозрительно, потому что кажется, что потоки могут дать довольно большой прирост производительности в некоторых ситуациях.
Поэтому мой вопрос заключается в том, что когда я сталкиваюсь с ситуацией, когда потоки и процессы могут справляться достаточно хорошо, мне следует использовать процессы или потоки? Например, если я писал веб-сервер, я должен использовать процессы или потоки (или их комбинацию)?
linux
performance
multithreading
process
user17918
источник
источник
Ответы:
В Linux используется модель потоков 1-1, в которой (для ядра) нет различий между процессами и потоками - все это просто выполняемая задача. *
В Linux системный вызов
clone
клонирует задачу с настраиваемым уровнем общего доступа, среди которых:CLONE_FILES
: использовать одну и ту же таблицу дескрипторов файлов (вместо создания копии)CLONE_PARENT
: не устанавливать отношения родитель-потомок между новой задачей и старой (в противном случае child'sgetppid()
= parent'sgetpid()
)CLONE_VM
: использовать то же пространство памяти (вместо создания копии COW )fork()
вызываетclone(
наименьшее совместное использование)
иpthread_create()
вызовыclone(
наиболее общего доступа)
. **fork
Стоимостьpthread_create
копирования немного выше, чем копирование таблиц и создание сопоставлений COW для памяти, но разработчики ядра Linux постарались (и преуспели) в минимизации этих затрат.Переключение между задачами, если они совместно используют одно и то же пространство памяти и различные таблицы, будет стоить чуть-чуть дешевле, чем если бы они не были общими, потому что данные могут быть уже загружены в кэш. Однако переключение задач по-прежнему происходит очень быстро, даже если ничего не передается - это то, что разработчики ядра Linux стараются обеспечить (и добиваются успеха в этом).
На самом деле, если вы работаете в многопроцессорной системе, отказ от совместного использования может быть полезен для производительности: если каждая задача выполняется на другом процессоре, синхронизация общей памяти обходится дорого.
* Упрощенный
CLONE_THREAD
вызываетCLONE_SIGHAND
передачу сигналов для совместного использования (что необходимо , что разделяет таблицу обработчиков сигналов).** Упрощено. Существуют
SYS_fork
иSYS_clone
системные вызовы, и системные вызовы, но в ядре обеsys_fork
иsys_clone
являются очень тонкими оболочками для одной и той жеdo_fork
функции, которая сама по себе является тонкой оболочкойcopy_process
. Да, терминыprocess
,thread
иtask
используются довольно взаимозаменяемо в ядре Linux ...источник
socket
,bind
,listen
,fork
, а затем несколько процессовaccept
соединения на одном сокете. Процесс может перестать принимать, если он занят, и ядро направит входящие соединения другому процессу (если никто не слушает, ядро будет стоять в очереди или отбрасываться, в зависимости отlisten
отставания). У вас нет намного большего контроля над распределением работы, чем обычно, но обычно этого достаточно!clone()
определить, какие ресурсы являются общими. Задача также может потребоватьunshare()
ресурсы в любой более поздний момент времени.task_struct
для каждой задачи. Это часто называют «процессом» во всем коде ядра, но оно соответствует каждому выполняемому потоку. Нетprocess_struct
; если кучаtask_struct
s связана друг с другом своимthread_group
списком, то это один и тот же «процесс» для пользовательского пространства. Есть небольшая специальная обработка «потоков», например, все дочерние потоки останавливаются на fork и exec, и в них отображается только «основной» потокls /proc
. Каждый поток доступен через/proc/pid
, независимо от того, включен он в список/proc
или нет.clone(CLONE_THREAD | CLONE_VM | CLONE_SIGHAND))
даст вам новый «поток», который не разделяет рабочий каталог, файлы или блокировки, в то время какclone(CLONE_FILES | CLONE_FS | CLONE_IO)
даст вам «процесс», который делает. Основная система создает задачи путем клонирования;fork()
иpthread_create()
являются просто библиотечными функциями, которые вызывают по-clone()
разному (как я написал в этом ответе).Linux (да и вообще Unix) дает вам третий вариант.
Вариант 1 - процессы
Создайте автономный исполняемый файл, который обрабатывает некоторую часть (или все части) вашего приложения, и вызывайте его отдельно для каждого процесса, например, программа запускает свои копии для делегирования задач.
Вариант 2 - темы
Создайте автономный исполняемый файл, который запускается с одного потока, и создайте дополнительные потоки для выполнения некоторых задач.
Вариант 3 - вилка
Доступно только под Linux / Unix, это немного отличается. Разветвленный процесс на самом деле является своим собственным процессом со своим собственным адресным пространством - дочерний элемент не может (обычно) ничего сделать, чтобы повлиять на адресное пространство своего родителя или братьев и сестер (в отличие от потока), поэтому вы получаете дополнительную устойчивость.
Однако страницы памяти не копируются, они копируются при записи, поэтому обычно используется меньше памяти, чем вы можете себе представить.
Рассмотрим программу веб-сервера, которая состоит из двух этапов:
Если вы используете потоки, шаг 1 будет выполнен один раз, а шаг 2 - в нескольких. Если вы использовали «традиционные» процессы, шаги 1 и 2 должны были бы повторяться для каждого процесса, а память для хранения данных конфигурации и времени выполнения дублировалась. Если вы использовали fork (), то вы можете выполнить шаг 1 один раз, а затем fork (), оставив данные и конфигурацию времени выполнения в памяти, нетронутыми, а не скопированными.
Так что на самом деле есть три варианта.
источник
Это зависит от многих факторов. Процессы более тяжелые, чем потоки, и имеют более высокую стоимость запуска и завершения работы. Межпроцессное взаимодействие (IPC) также сложнее и медленнее, чем межпотоковое взаимодействие.
И наоборот, процессы более безопасны и безопасны, чем потоки, поскольку каждый процесс выполняется в своем собственном виртуальном адресном пространстве. Если происходит сбой одного процесса или переполнение буфера, это никак не влияет на любой другой процесс, тогда как при сбое потока он удаляет все другие потоки в процессе, а если поток имеет переполнение буфера, он открывается дыра в безопасности во всех потоках.
Таким образом, если модули вашего приложения могут работать в основном независимо при небольшом обмене данными, вам, вероятно, следует использовать процессы, если вы можете позволить себе затраты на запуск и завершение работы. Падение производительности IPC будет минимальным, и вы будете немного безопаснее от ошибок и брешей в безопасности. Если вам нужен каждый бит производительности, который вы можете получить или иметь много общих данных (таких как сложные структуры данных), используйте потоки.
источник
Другие обсуждали соображения.
Возможно, важным отличием является то, что в Windows процессы тяжелые и дорогие по сравнению с потоками, а в Linux разница намного меньше, поэтому уравнение балансирует в другой точке.
источник
Когда-то был Unix, и в этом старом добром Unix было много накладных расходов на процессы, поэтому некоторые умные люди делали то, что создавали потоки, которые совместно использовали бы то же адресное пространство с родительским процессом, и им нужен был только сокращенный контекст. переключатель, который сделает переключение контекста более эффективным.
В современном Linux (2.6.x) нет большой разницы в производительности между переключением контекста процесса по сравнению с потоком (только поток MMU является дополнительным для потока). Существует проблема с общим адресным пространством, что означает, что неисправный указатель в потоке может повредить память родительского процесса или другого потока в том же адресном пространстве.
Процесс защищен MMU, поэтому неисправный указатель просто вызовет сигнал 11 и не повредит.
В общем, я бы использовал процессы (не слишком много издержек при переключении контекста в Linux, но защита памяти из-за MMU), но я хотел бы подумать, если мне понадобится класс планировщика реального времени, который представляет собой другую чашку чая.
Как вы думаете, почему потоки имеют такой большой прирост производительности в Linux? У вас есть данные для этого, или это просто миф?
источник
Насколько тесно связаны ваши задачи?
Если они могут жить независимо друг от друга, то использовать процессы. Если они полагаются друг на друга, то используйте темы. Таким образом, вы можете убить и перезапустить плохой процесс, не вмешиваясь в работу других задач.
источник
Чтобы еще больше усложнить ситуацию, существует такая вещь, как локальное хранилище потоков и общая память Unix.
Локальное хранилище потоков позволяет каждому потоку иметь отдельный экземпляр глобальных объектов. Единственный раз, когда я использовал его, был при создании среды эмуляции в linux / windows для кода приложения, работающего в RTOS. В RTOS каждая задача была процессом с собственным адресным пространством, в среде эмуляции каждая задача была потоком (с общим адресным пространством). Используя TLS для таких вещей, как синглеты, мы смогли создать отдельный экземпляр для каждого потока, как в «реальной» среде RTOS.
Совместно используемая память может (очевидно) дать вам преимущества в производительности, если несколько процессов обращаются к одной и той же памяти, но за счет риска / риска правильной синхронизации процессов. Один из способов сделать это состоит в том, чтобы один процесс создал структуру данных в разделяемой памяти, а затем отправил дескриптор этой структуры через традиционное межпроцессное взаимодействие (например, именованный канал).
источник
В моей недавней работе с LINUX важно знать о библиотеках. Если вы используете потоки, убедитесь, что все библиотеки, которые вы можете использовать между потоками, являются поточно-ориентированными. Это обожгло меня пару раз. Примечательно, что libxml2 не поддерживает потоки из коробки. Он может быть скомпилирован с поддержкой потоков, но это не то, что вы получаете при установке aptitude.
источник
Я должен согласиться с тем, что вы слышали. Когда мы тестируем наш кластер (
xhpl
и тому подобное), мы всегда получаем значительно лучшую производительность с процессами над потоками.</anecdote>
источник
Решение между потоком / процессом немного зависит от того, для чего вы будете его использовать. Одно из преимуществ процесса заключается в том, что он имеет PID и может быть уничтожен без прерывания родительского процесса.
Для реального примера веб-сервера apache 1.3 использовался только для поддержки нескольких процессов, но в 2.0 они добавили абстракцию, чтобы вы могли переключаться между ними. Похоже, комментарии согласны с тем, что процессы более устойчивы, но потоки могут дать немного лучшую производительность (за исключением окон, в которых производительность процессов отстой и вы хотите использовать только потоки).
источник
В большинстве случаев я бы предпочел процессы над потоками. Потоки могут быть полезны, когда у вас относительно небольшая задача (издержки процесса >> время, затрачиваемое каждым разделенным блоком задач), и между ними требуется совместное использование памяти. Подумайте, большой массив. Также (оффтоп), обратите внимание, что если загрузка вашего процессора составляет 100 процентов или близка к ней, многопоточность или обработка не принесут никакой пользы. (на самом деле это ухудшится)
источник
Потоки -> Потоки разделяют пространство памяти, это абстракция ЦП, она легкая. Процессы -> Процессы имеют свое собственное пространство памяти, это абстракция компьютера. Чтобы распараллелить задачу, вам нужно абстрагировать процессор. Однако преимуществом использования процесса над потоком является безопасность, стабильность, в то время как поток использует меньше памяти, чем процесс, и обеспечивает меньшую задержку. Примером с точки зрения сети будет Chrome и Firefox. В случае Chrome каждая вкладка - это новый процесс, поэтому использование памяти в chrome выше, чем в Firefox, а обеспеченная безопасность и стабильность лучше, чем в Firefox. Безопасность, обеспечиваемая Chrome, лучше, поскольку каждая вкладка представляет собой новый процесс, который не может быть отслежен в пространстве памяти данного процесса.
источник
Я думаю, что все проделали отличную работу, отвечая на ваш вопрос. Я просто добавляю больше информации о потоке против процесса в Linux, чтобы уточнить и обобщить некоторые предыдущие ответы в контексте ядра. Итак, мой ответ касается специфичного для ядра кода в Linux. Согласно документации ядра Linux, нет четкого различия между потоком и процессом, за исключением того, что поток использует общее виртуальное адресное пространство в отличие от процесса. Также обратите внимание, что ядро Linux использует термин «задача» для обозначения процесса и потока в целом.
«Нет внутренних структур, реализующих процессы или потоки, вместо этого есть структура task_struct, которая описывает абстрактный блок планирования, называемый задачей»
Кроме того, согласно Линусу Торвальдсу, вы НЕ должны вообще думать о процессе и потоке, поскольку он слишком ограничен, и единственное отличие заключается в COE или контексте выполнения в терминах «отделения адресного пространства от родительского» или общего адресного пространства. На самом деле он использует пример веб - сервера , чтобы сделать его пункт здесь (который настоятельно рекомендую прочитать).
Полный кредит документации ядра Linux
источник
Если вам нужно делиться ресурсами, вы действительно должны использовать потоки.
Также учтите тот факт, что переключение контекста между потоками намного дешевле, чем переключение контекста между процессами.
Я не вижу причин явно использовать отдельные процессы, если у вас нет веских причин для этого (безопасность, проверенные тесты производительности и т. Д.)
источник