mweerden: NT с первого дня разрабатывался для многопользовательского режима, так что это не совсем причина. Однако вы правы в том, что создание процесса играет менее важную роль в NT, чем в Unix, поскольку NT, в отличие от Unix, отдает предпочтение многопоточности над многопроцессорностью.
Роб, это правда, что при использовании COW форк относительно дешев, но на самом деле за форком в основном следует exec. И исполнительный директор также должен загрузить все изображения. Поэтому обсуждение производительности вилки - это только часть правды.
При обсуждении скорости создания процесса, вероятно, будет хорошей идеей различать NT и Windows / Win32. Что касается NT (т.е. самого ядра), я не думаю, что создание процесса (NtCreateProcess) и создание потока (NtCreateThread) происходит значительно медленнее, чем в среднем Unix. Может быть, происходит немного больше, но я не вижу здесь основной причины разницы в производительности.
Однако, если вы посмотрите на Win32, вы заметите, что он добавляет довольно много накладных расходов на создание процесса. Во-первых, он требует, чтобы CSRSS был уведомлен о создании процесса, который включает LPC. Для этого требуется как минимум загрузка ядра 32, и он должен выполнить ряд дополнительных операций по учету, которые необходимо выполнить, прежде чем процесс будет считаться полноценным процессом Win32. И давайте не будем забывать обо всех дополнительных накладных расходах, связанных с синтаксическим анализом манифестов, проверкой того, требуется ли для изображения прокладка совместимости, проверкой применения политик ограниченного использования программ, yada yada.
Тем не менее, я вижу общее замедление в сумме всех тех мелочей, которые необходимо сделать в дополнение к необработанному созданию процесса, виртуального пространства и начального потока. Но, как было сказано в начале, из-за предпочтения многопоточности над многозадачностью единственное программное обеспечение, на которое серьезно влияют эти дополнительные расходы, - это плохо портированное программное обеспечение Unix. Хотя эта ситуация меняется, когда такие программы, как Chrome и IE8, внезапно заново открывают для себя преимущества многопроцессорности и начинают часто запускать и отключать процессы ...
В Unix есть системный вызов fork, который «разбивает» текущий процесс на два и дает вам второй процесс, идентичный первому (по модулю возврата из вызова fork). Поскольку адресное пространство нового процесса уже запущено и работает, это должно быть дешевле, чем вызов CreateProcess в Windows и загрузка исполняемого образа, связанных библиотек DLL и т. Д.
В случае вилки ОС может использовать семантику «копирование при записи» для страниц памяти, связанных с обоими новыми процессами, чтобы гарантировать, что каждый из них получит свою собственную копию страниц, которые они впоследствии изменяют.
источник
Добавим к тому, что сказал JP: большая часть накладных расходов относится к запуску процесса Win32.
Ядро Windows NT действительно поддерживает вилку COW. SFU (среда Microsoft UNIX для Windows) использует их. Однако Win32 не поддерживает вилку. Процессы SFU не являются процессами Win32. SFU ортогонален Win32: обе подсистемы среды построены на одном ядре.
В дополнение к внепроцессным вызовам LPC
CSRSS
в XP и более поздних версиях существует внепроцессный вызов подсистемы совместимости приложений для поиска программы в базе данных совместимости приложений. Этот шаг вызывает достаточно накладных расходов, поэтому Microsoft предоставляет параметр групповой политики для отключения механизма совместимости на WS2003 по соображениям производительности.Библиотеки времени выполнения Win32 (kernel32.dll и т. Д.) Также выполняют множество операций чтения реестра и инициализации при запуске, что не относится к UNIX, SFU или собственным процессам.
Нативные процессы (без подсистемы окружения) создаются очень быстро. SFU делает намного меньше, чем Win32 для создания процессов, поэтому его процессы также создаются быстро.
ОБНОВЛЕНИЕ НА 2019 ГОД: добавлен LXSS: подсистема Windows для Linux
Заменой SFU для Windows 10 является подсистема среды LXSS. Это 100% режим ядра и не требует каких-либо IPC, которые по-прежнему используются в Win32. Системный вызов для этих процессов направлен непосредственно на lxss.sys / lxcore.sys, поэтому вызов fork () или другого процесса, создающий, стоит всего 1 системный вызов для создателя, всего. [Область данных, называемая экземпляром] отслеживает все процессы LX, потоки и состояние выполнения.
Процессы LXSS основаны на собственных процессах, а не на процессах Win32. Все специфические для Win32 вещи, такие как механизм совместимости, вообще не задействованы.
источник
В дополнение к ответу Роба Уокера: в настоящее время у вас есть такие вещи, как собственная библиотека потоков POSIX - если хотите. Но долгое время единственным способом «делегировать» работу в мире unix было использование fork () (и это все еще предпочитается во многих, многих случаях). например, какой-то сервер сокетов
Поэтому реализация форка должна быть быстрой, и со временем было реализовано множество оптимизаций. Microsoft одобрила CreateThread или даже волокна вместо создания новых процессов и использования межпроцессного взаимодействия. Я считаю нечестным сравнивать CreateProcess с fork, поскольку они не взаимозаменяемы. Вероятно, более уместно сравнить fork / exec с CreateProcess.источник
Я думаю, что ключом к этому вопросу является историческое использование обеих систем. Windows (и до этого DOS) изначально были однопользовательскими системами для персональных компьютеров. Таким образом, этим системам обычно не нужно постоянно создавать множество процессов; (очень) проще говоря, процесс создается только тогда, когда его запрашивает одинокий пользователь (а мы, люди, не работаем очень быстро, условно говоря).
Системы на основе Unix изначально были многопользовательскими системами и серверами. Особенно для последних нередки случаи, когда процессы (например, почтовые или http-демоны) отделяются от процессов для обработки определенных заданий (например, для обслуживания одного входящего соединения). Важным фактором в этом является дешевый
fork
метод (который, как упоминал Роб Уокер ( 47865 ), изначально использует ту же память для вновь созданного процесса), который очень полезен, поскольку новый процесс сразу получает всю необходимую информацию.Ясно, что, по крайней мере, исторически потребность для систем на базе Unix в быстром создании процессов намного больше, чем для систем Windows. Я думаю, что это все еще так, потому что системы на основе Unix все еще очень ориентированы на процессы, в то время как Windows, из-за своей истории, вероятно, была более ориентирована на потоки (потоки полезны для создания отзывчивых приложений).
Отказ от ответственности: я ни в коем случае не эксперт в этом вопросе, так что простите меня, если я ошибся.
источник
Кажется, есть много оправданий типа "так лучше".
Я думаю, людям было бы полезно прочитать "Showstopper"; книга о разработке Windows NT.
Вся причина, по которой службы запускаются как DLL в одном процессе в Windows NT, заключалась в том, что они были слишком медленными как отдельные процессы.
Если вы опуститесь и испачкаетесь, вы обнаружите, что проблема заключается в стратегии загрузки библиотеки.
В Unices (в общем) сегменты кода общих библиотек (DLL) фактически являются общими.
Windows NT загружает копию DLL для каждого процесса, так как она манипулирует сегментом кода библиотеки (и сегментом исполняемого кода) после загрузки. (Сообщает, где ваши данные?)
Это приводит к тому, что сегменты кода в библиотеках не подлежат повторному использованию.
Итак, создание процесса NT на самом деле довольно дорого. И с другой стороны, это делает DLL не заметной экономией в памяти, а шансом для проблем с зависимостями между приложениями.
Иногда инженеру выгодно сделать шаг назад и сказать: «А теперь, если бы мы собирались спроектировать это по-настоящему отстойным, как бы это выглядело?»
Когда-то я работал со встроенной системой, которая была довольно темпераментной, и однажды взглянув на нее, я понял, что это резонаторный магнетрон с электроникой в микроволновом резонаторе. После этого мы сделали его более стабильным (и менее похожим на микроволновку).
источник
Краткий ответ - «программные уровни и компоненты».
Архитектура Windows SW имеет несколько дополнительных уровней и компонентов, которых нет в Unix или которые упрощены и обрабатываются внутри ядра в Unix.
В Unix fork и exec - это прямые вызовы ядра.
В Windows API ядра не используется напрямую, есть win32 и некоторые другие компоненты поверх него, поэтому создание процесса должно проходить через дополнительные уровни, а затем новый процесс должен запускаться или подключаться к этим уровням и компонентам.
В течение довольно долгого времени исследователи и корпорации пытались разбить Unix примерно таким же способом, обычно основывая свои эксперименты на ядре Mach ; хорошо известный пример является OS X. . Однако каждый раз, когда они пытаются, это становится настолько медленным, что они, по крайней мере, частично объединяют части обратно в ядро либо навсегда, либо для производственных поставок.
источник
Поскольку в некоторых ответах, похоже, есть какое-то оправдание MS-Windows, например
Теперь посмотрим на факты, в чем разница в производительности?
Данные взяты из http://www.bitsnbites.eu/benchmarking-os-primitives/ .
Поскольку предвзятость неизбежна, резюмируя, я сделал это в пользу MS-Windows
Hardware для большинства тестов i7 8 core 3.2GHz. Кроме Raspberry-Pi под управлением Gnu / Linux
Примечания: В Linux
fork
это быстрее, чем предпочтительный метод MS-WindowCreateThread
.Числа для операций типа создания процесса (потому что значение для Linux трудно увидеть на диаграмме).
В порядке скорости, от самой быстрой к самой медленной (числа - время, маленькие - лучше).
Цифры для других измерений
источник
Все это плюс тот факт, что на машине Win, скорее всего, антивирусное программное обеспечение сработает во время CreateProcess ... Обычно это самое большое замедление.
источник
Также стоит отметить, что модель безопасности в Windows намного сложнее, чем в ОС на базе UNIX, что добавляет много накладных расходов при создании процесса. Еще одна причина, по которой многопоточность предпочтительнее многопроцессорной обработки в Windows.
источник
fork()