Что такое fork процесса
Что проверяют
Знаете ли вы, как операционная система создаёт процессы, и понимаете ли, почему в Go этот механизм почти не используют напрямую. Вопрос системный: важно, отличаете ли вы процесс от потока и горутины и что происходит с памятью и дескрипторами после вызова.
Как отвечать
fork это системный вызов UNIX, создающий новый процесс копией текущего. Вызывается один раз, возвращает управление дважды: родителю отдаётся идентификатор ребёнка, ребёнку ноль, при ошибке отрицательное значение. Ребёнок наследует адресное пространство, открытые дескрипторы и точку выполнения.
Копия ленивая: страницы помечаются copy-on-write и дублируются только при первой записи. Дорого не это, а копирование таблиц страниц у процесса с большим резидентным объёмом и последующие промахи при записи.
Рабочая связка почти всегда fork плюс exec: ребёнок сразу подменяет образ другой программой, так устроен запуск внешней команды из оболочки.
Дальше главное про Go. Голого fork в стандартной библиотеке нет намеренно: рантайм многопоточный, а fork переносит в ребёнка только вызвавший поток. Мьютексы, захваченные в этот момент другими потоками, останутся захваченными навсегда, планировщик и сборщик мусора окажутся в неконсистентном состоянии. Поэтому язык даёт только неразрывную связку fork и exec: пакет os/exec и низкоуровневый syscall.ForkExec, где между двумя вызовами не делается ничего лишнего. Параллелизм внутри процесса в Go закрывают горутины, а отдельный процесс нужен ради изоляции или чужого исполняемого файла.
Где спотыкаются
Утверждают, что fork физически копирует всю память родителя. На современных ядрах копируются только таблицы страниц, а данные по мере записи. Отсюда неверный вывод, что форк гигабайтного процесса обязательно занимает секунды.
Забывают про уборку: если родитель не вызвал ожидание, завершившийся ребёнок висит зомби и держит запись в таблице процессов. На нагруженном сервисе это кончается исчерпанием лимита.
Предлагают форкнуть процесс на Go и продолжить в ребёнке обычный код с горутинами. Ребёнок получает один поток и заблокированные чужие локи, поэтому такой код зависает не сразу, а на первой же аллокации или обращении к рантайму.