2015-07-16 4 views
1

У меня есть это большое серверное программное обеспечение, которое может поддерживать 4-8 ГБ памяти.Выполнение внешней программы при форкировании не рекомендуется

Это делает fork-exec громоздким, поскольку сама вилка может занять значительное время, а поведение по умолчанию, по-видимому, заключается в том, что вилка завершится неудачно, если для копии всей резидентной памяти недостаточно памяти.

Так как это начало показывать как самое жаркое место (60% времени, проведенного в вилке) при профилировании, мне нужно обратиться к нему.

Что было бы самым простым способом избежать рутинной работы fork-exec?

+3

Вы не указали ОС, но в Linux fork() использует copy-on-write, поэтому я не ожидаю проблемы с производительностью. –

+0

Если вы хотите избежать копирования родительской памяти, возможно, 'vfork' может помочь. – phoxis

+1

Трудно поверить, что 60% вашего времени потрачено на развилку. Сколько вилок вы делаете в секунду? – Marian

ответ

6

Вы в основном не избежать fork(2) (или эквивалентный clone(2) ... системный вызов, или устаревшую vfork, которые я не рекомендую использовать) + execve(2) начать внешнюю команду (а-ля system(3) или а-ля posix_spawn) на Linux и (возможно) MacOSX и большинство других систем Unix или POSIX.

Почему вы считаете, что это проблема? И виртуальное адресное пространство процесса 8GB сегодня не имеет большого значения (по крайней мере, на машинах с 8 Гбайт или 16 Гбайт оперативной памяти, как у моего рабочего стола). Вам не требуется в два раза больше оперативной памяти (но вам нужно место подкачки) благодаря ленивым методам copy-on-write, используемым всеми последними Linux-файлами Unixes &.

Возможно, вы можете поверить, что пространство подкачки может быть проблемой. В Linux вы можете добавить пространство подкачки, возможно, путем замены на файл; просто запустить как корень:

dd if=/dev/zero of=/var/tmp/myswap bs=1M count=32768 
mkswap /var/tmp/myswap 
swapon /var/tmp/myswap 

(конечно, убедитесь, что /var/tmp/ не TMPFS установлена ​​файловая система, но сидит на каком-то диске, возможно, SSD один ....)

Когда вы надеваете» нужно больше места для подкачки, запустите swapoff /var/tmp/myswap ....

Вы также можете запустить какой-то внешний процесс оболочки в начале вашей программы (à la popen), а позже вы можете отправить команды оболочки на него. Посмотрите на моей программе execicar.c для вдохновения, или использовать его, если он подходит (я написал 10 лет назад для подобных целей, но я забыл подробность)

Альтернативно вилка в начале вашей программы некоторых интерпретатор (Lua, Guile. ..) и отправить некоторые команды ему.

Запуск больше, чем несколько десятков команд в секунду (начиная с любой внешней программой) не является разумным, и их следует рассматривать как дизайн ошибку, ИМХО. Возможно, команды, которые вы используете, могут быть заменены встроенными функциями (например, /bin/ls могут быть выполнены с stat, readdir, globфункциями ...). Возможно, вы можете подумать о , добавивdlopen(3) ) к вашему коду (и запускать функции из плагинов, а не запускать очень часто одни и те же программы). Или, возможно, встройте в свой код переводчика (Lua, Guile, ...).

В качестве примера, для веб-серверов, найдите старые CGI vs FastCGI или HTTP-пересылку (например,URL redirection) или встроенный PHP или HOP или Ocsigen

+0

В сообщении Let_Me_Be подумайте, когда вы fork в программе 4-8GB, эта программа будет использовать память 4-8 ГБ * 2 – eroween

+0

@ LouisMartin-Pierrat Нет, она не будет использовать память, но вилка потерпит неудачу, если у вас нет места для копирования. –

+0

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

2

Это делает вилочного Exec громоздким, так как сама вилка может занять значительное время

Это верно только наполовину. Вы не указали ОС, но fork(2) довольно оптимизирован в Linux (и я верю в другие варианты UNIX), используя copy-on-write. Copy-on-write означает, что операционная система не будет копировать все адресное пространство родительской памяти, пока ребенок (или родительский) не будет записывать в память. Таким образом, вы можете быть уверены, что если у вас есть родительский процесс с использованием 8 ГБ памяти, а затем вы используете fork, вы не будете использовать 16 ГБ памяти - , особенно, если ребенок выполнит() что-то немедленно.

вилка будет повреждена, если не хватает памяти для копии всей памяти .

No. только накладные расходы, понесенные fork(2) является копией и распределение структуры задач для ребенка, выделение из PID и копирования таблицы страниц родителя. fork(2) будет not сбой, если памяти недостаточно, чтобы скопировать адресное пространство всего родителя, это не удастся, если памяти недостаточно, чтобы выделить новую структуру задачи и таблицы страниц. Он также может выйти из строя, если достигнуто максимальное количество процессов для пользователя. Вы можете подтвердить это в man 2 fork (ПРИМЕЧАНИЕ: см. Комментарии ниже).

Если вы все еще не хотите использовать fork(2), вы можете использовать vfork(2), который вообще не копирует - он даже не копирует таблицы страниц - все разделяется с родительским. Вы можете использовать это для создания нового дочернего процесса с незначительными служебными данными, а затем exec(). Имейте в виду, что vfork(2) блокирует вызывающий поток до тех пор, пока ребенок не выйдет или не вызовет одну из семи функций exec(). Вы также не должны изменять память внутри дочернего процесса до вызова любой из функций exec().

+0

Можете ли вы назвать vfork в потоке? (чтобы избежать этой части: vfork (2) блокирует родительский элемент до тех пор, пока ребенок не выйдет или не вызовет одну из семи функций exec(), используя пул работников для запуска exec + vfork, может быть хорошей идеей, если вы можете использовать поток для запуск vfork – eroween

+0

@ LouisMartin-Pierrat Да, вы можете. Фактически, технически я должен был сказать * 'vfork (2)' блокирует вызывающий поток, пока ребенок не выйдет или не вызовет exec() *. –

+0

Итак, вы можете использовать рабочий пул для запуска многих процессов? – eroween

1

Вы упомянули, что можете fork + exec 10k раз в секунду. Это звучит очень чрезмерно. Считаете ли вы, что делаете то, что вы делаете, в демон? Или, может быть, реализовать эти внешние программы внутри своего приложения? Звучит очень изворотливо, что нужно так сильно размазать.

fork скорее всего, начнет сбой для вас, несмотря на то, что у вас есть память, чтобы поддержать его, потому что у вас есть вкус Linux, который отключил (или превзошел) память. Проверьте файл /proc/sys/vm/overcommit_memory. Если это 1, то мое предположение ошибочно, и есть что-то еще странное. Если это 0, вам не разрешается перекомбинировать вообще. Если это 2, вам нужно прочитать документацию о том, как именно это настраивается.

Одно из решений, упомянутых выше, просто добавляет swap (который никогда не будет использоваться).

Другим решением является внедрение небольшого демона, который будет принимать команды и выполнять эти вилки и execs, для того, чтобы вы возвращали все необходимые вам данные.

N.B. fork большого процесса теоретически может быть столь же быстрым, как небольшой процесс. Производительность вилки определяется тем, сколько у вас памяти, а не сколько памяти они покрывают. Настройка копирования на запись выполняется для каждого сопоставления.За исключением того, что на некоторых операционных системах настройка COW анонимных сопоставлений линейна по объему памяти в этих сопоставлениях, но я не знаю, что здесь делает Linux, в последний раз, когда я изучал систему VM в Linux, было более 15 лет назад.

Смежные вопросы