2009-10-14 2 views
6

Хотелось бы высказать некоторые мысли о том, является ли использование fork {} в «background» процессом из приложения rails такой хорошей идеей или нет ...с использованием ядра fork для фоновых процессов, профи? минусы?

Из того, что я собираю fork {my_method; Процесс # setsid} действительно делает то, что он должен делать.

1) создает еще процессы с другой PID

2) не прерывает процесс вызова (например, он по-прежнему без ждет развилка до конца)

3) не выполняет ребенка до тех пор, он заканчивает

.. это классно, но это хорошая идея? Что именно делает вилка? Создает ли он дублирующий экземпляр моего всего рельса mongrel/пассажира в памяти? Если так, это было бы очень плохо. Или это как-то делает это, не потребляя огромного количества памяти.

Моя конечная цель состояла в том, чтобы покончить с моей системой фон демона/очереди в пользу разветвление этих процессов (в первую очередь отправки сообщений электронной почты) - но если это не будет экономить память, то это, безусловно, шаг в неправильном направлении

+0

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

+0

сервер очередей ++. Возможно, вы захотите проверить MQ (http://github.com/mdarby/mq) для очередей электронной почты. Я использовал его в производстве в течение нескольких месяцев без каких-либо проблем. –

ответ

0

Семантика вилки - это копирование всего пространства памяти процесса в новый процесс, но многие (большинство?) Систем будут делать это, просто сделав копию таблиц виртуальной памяти и маркируя ее копированием на запись. Это означает, что (по крайней мере, по крайней мере) он не использует гораздо больше физической памяти, достаточной для создания новых таблиц и других структур данных для каждого процесса.

Тем не менее, я не уверен, насколько хорошо Ruby, RoR и т. Д. Взаимодействует с копированием на запись. В частности, сбор мусора может быть проблематичным, если он касается многих страниц памяти (что приводит к их копированию).

+0

Я слышал обо всех вещах о COW ... довольно уверен, что некоторые из ветвей 1.8 не поддерживали его, но REE делает (?). И я слышал, что 1,9 делает и не поддерживает COW. Это сказало, * даже если он *, представьте мои рельсы действия: Защиту Foo do_stuff fork_and_send_email do_more_stuff конца даже если вилка КПС будет не исходное местоположение памяти мгновенно изменяется (из-за того, что приходит после него) и тем самым подстрекает копию? Даже если вилка была последним вызовом метода. Я бы предположил, что рельсы по-прежнему работают после этого, не говоря уже ... следующий запрос, поступивший в тот же процесс. jsharpe

+0

dammit, комментируя форматирование: def foo; do_stuff; fork_and_send_email; do_more_stuff; end – jsharpe

+0

Ну, да, какое-то копирование произойдет, но, надеюсь, это будет не весь объем памяти процесса; скорее, это будут отдельные страницы памяти здесь и там (на страницах памяти x86 обычно 4 килобайта). – wdebeaum

4

Вилка делает копию всего вашего процесса и, в зависимости от того, как вы подключены к серверу приложений, также является копией этого файла. Как было отмечено в другом обсуждении, это делается с copy-on-write, так что это терпимо. В конце концов, Unix построен вокруг fork (2), поэтому он должен управлять им довольно быстро. Обратите внимание, что все частично буферизованные входы/выходы, открытые файлы и множество других материалов также копируются, а также состояние программы, которая подгружается, чтобы записать их, что было бы неверно.

У меня есть несколько мыслей:

  • Вы используете Action Mailer? Похоже, что электронная почта будет легко сделана с AM или Process.popen чего-то. (Popen сделает вилку, но за ней сразу следует exec.)
  • немедленно избавиться от всего этого состояния, выполнив Process.exec другого рубинового интерпретатора плюс ваши функциональные возможности. Если для передачи слишком много состояний или вам действительно нужно использовать эти дублированные дескрипторы файлов, вы можете сделать что-то вроде IO#popen, чтобы вы могли отправить работу подпроцесса. Система автоматически поделит страницы, содержащие текст интерпретатора Ruby подпроцесса с родителем.
  • В дополнение к вышесказанному, вы можете рассмотреть возможность использования драгоценного камня daemons. В то время как процесс ваших рельсов уже является демоном, использование драгоценного камня может облегчить работу одной фоновой задачи в качестве сервера пакетных заданий и упростить запуск, мониторинг, перезапуск, если он бомбит, и выключить, когда вы это сделаете. ,
  • если вы выйти из fork(2) эд подпроцесса, используйте exit! вместо exit
  • , имеющий очередь сообщений и демон, уже настроенный, как вы делаете, своего рода звучит как хорошее решение для меня :-)
1

Имейте в виду, что это не позволит вам использовать JRuby on Rails, поскольку fork() не реализован (пока).