Другие ответы хорошо объяснили, почему fork
быстрее, чем кажется, и как он изначально появился.Но есть также веские основания для сохранения комбо fork
+ exec
, и это гибкость, которую он предлагает.
Часто, когда порождает дочерний процесс, необходимо выполнить подготовительные шаги, прежде чемказнить ребенка.Например: вы можете создать пару каналов, используя pipe
(читатель и записывающее устройство), затем перенаправить stdout
или stderr
дочернего процесса на записывающее устройство или использовать считыватель как stdin
- илилюбой другой дескриптор файла, в этом отношении.Или вы можете установить переменные окружения (но только в дочернем).Или установите ограничения ресурсов с помощью setrlimit
, чтобы ограничить количество ресурсов, которое может использовать дочерний элемент (без ограничения родительского элемента).Или измените пользователей с помощью setuid
/ seteuid
(без изменения родительского элемента).И т. Д. И т. Д.
Конечно, вы можете сделать все это с помощью гипотетической функции create_process
.Но это много вещей для покрытия!Почему бы не предложить гибкость при запуске fork
, делать все, что вы хотите, чтобы настроить дочерний процесс, а затем запускать exec
?
Кроме того, иногда вам даже совсем не нужен дочерний процесс.Если ваша текущая программа (или сценарий) существует исключительно для выполнения некоторых из этих шагов установки, и последнее, что она собирается сделать, это запустить новый процесс, тогда зачем вообще два процесса?Вы можете использовать exec
, чтобы просто заменить текущий процесс, освобождая собственную память и PID.
Форкинг также допускает некоторое полезное поведение в отношении наборов данных только для чтения.Например, у вас может быть родительский процесс, который собирает и индексирует огромное количество данных, а затем отбирает у детей-работников выполнение обходов и вычислений на основе этих данных.Родителю не нужно никуда его сохранять, детям не нужно его читать, и вам не нужно выполнять какую-либо сложную работу с общей памятью.(В качестве примера: некоторые базы данных используют это как средство, чтобы дочерний процесс делал дамп базы данных в памяти на диск, не блокируя родительский процесс.)
Вышеприведенное также включает в себя любую программу, которая читает конфигурацию,база данных и / или набор файлов кода затем переходит к отключению дочерних процессов для обработки запросов и более эффективного использования многоядерных процессоров.Это включает в себя веб-серверы, но также и веб-приложения (или другие), особенно если эти приложения тратят значительное количество времени на запуск, просто читая и / или компилируя код более высокого уровня.
Форкинг также может быть полезенспособ управления памятью и избежание фрагментации, особенно для языков высокого уровня, которые используют автоматическое управление памятью (сборка мусора) и не имеют прямого контроля над своей структурой памяти.Если вашему процессу на короткое время требуется большой объем памяти для конкретной операции, вы можете разветвить и выполнить эту операцию, а затем выйти, освободив всю память, которую вы только что выделили.Напротив, если вы выполнили операцию в родительском объекте, у вас может быть значительная фрагментация памяти, которая может сохраняться в течение всего процесса - не очень хорошо для длительного процесса.
И наконец: как только вы примете этоfork
и exec
оба имеют свое собственное использование, независимо друг от друга, возникает вопрос - зачем создавать отдельную функцию, которая объединяет оба?Говорят, что философия Unix заключалась в том, чтобы ее инструменты «делали одно и делали это хорошо».Предоставляя вам fork
и exec
как отдельные строительные блоки - и делая каждый из них максимально быстрым и эффективным - они обеспечивают гораздо большую гибкость, чем одна функция create_process
.