Использование Process.spawn в качестве замены Process.fork - программирование

Использование Process.spawn в качестве замены Process.fork

Моя среда разработки - это Windows-машина с рубином 1.9.3p125 (RubyInstaller) и рельсы 3.2.8.

Одной из проблем, возникающих снова и снова при использовании сторонних драгоценных камней, является отсутствие fork() в Windows. Это в последнее время затрудняло мою способность использовать практически любой распределенный тестовый запуск gem (например, эти) из-за их зависимости от fork.

Некоторые старые вопросы в StackOverflow пытались найти решение этой проблемы, но были либо до добавления Process.spawn в ruby, либо из людей, вынужденных использовать более раннюю версию Ruby, по какой-то другой причине.

Одним из предлагаемых решений является использование Cygwin для получения поддержки fork(), что просто не может быть и речи - я думаю, что раньше я предпочел бы перейти на Linux.

В другом предлагаемом решении используется win32-process gem, чтобы получить поддержку fork(). Поддержка вилки была удалена из последней версии (0.7.0) и с использованием следующей самой старой версии (0.6.6), которая делает (видовую) поддержку fork, похоже, не работает, по крайней мере для запуска любого из распределенных тестируя драгоценные камни, которые я пробовал (Spork, Parallel tests, Hydra, Specjour, практически все из них). Интересно, что автор драгоценного камня ссылается, в readme, на Process.spawn, являющийся приемлемым обходным решением для Process.fork.

Я видел много информации, либо подразумевая, либо заявляя откровенно, что икру может использоваться в качестве замены fork в Windows с Ruby 1.9. Я потратил немало времени, играя с этим, в основном пытаясь заменить Process.fork на Process.spawn в некоторых из упомянутых драгоценных камней, без успеха. Мне кажется, что поведение похоже, но не совсем то же самое. Например, неясно, копирует ли вскрытие весь процесс так же, как это делает вилка, или просто создает новый процесс с предоставленными аргументами. Также неясно, допускает ли метод порождения другой метод ruby ​​в качестве аргумента или только системная команда. Документы, по-видимому, подразумевают, что это всего лишь команда, но метод работает (сортировка), но я могу делать что-то неправильно. Я думаю, что для некоторых вещей вилка использовалась только для создания "дешевой нити", в предыдущих версиях рубинов, которые не поддерживали потоки. Тем не менее, похоже, что эти распределенные тестовые камни могут законным образом полагаться на полную функциональность fork(), чтобы поддерживать состояние проекта и не загружать всю среду ruby ​​для каждого теста. Это немного отличается от моих обычных обязанностей и опыта программирования, поэтому я могу сделать некоторые неправильные предположения.

Итак, мой вопрос в том, может ли Process.spawn использоваться относительно просто для достижения того же результата, что и Process.fork, во всех случаях? Я начинаю подозревать, что нет, но если да, может кто-нибудь, пожалуйста, отправьте пример того, как можно было бы сделать преобразование?

4b9b3361

Ответ 1

EDIT. Существует один распространенный вариант использования fork(), который можно заменить на spawn() - комбинацию fork() - exec(). Многие старые (и современные) UNIX-приложения, когда они хотят создать другой процесс, будут сначала вилкой, а затем сделать вызов exec (exec заменяет текущий процесс другим). Это действительно не нужно fork(), поэтому его можно заменить на spawn(). Итак, это:

if(!fork())
  exec("dir")
end

можно заменить на:

Process.spawn("dir")

Если какой-либо из камней использует fork(), как это, исправление легко. В противном случае это почти невозможно.


EDIT: причина, по которой реализация fork() win32-process 'не работает, заключается в том, что (насколько я могу судить по документам) это в основном spawn(), что вообще не является fork().


Нет, я не думаю, что это можно сделать. Как видите, Process.spawn создает новый процесс с пустым состоянием по умолчанию и собственным кодом. Поэтому, хотя я могу сделать что-то вроде Process.spawn('dir'), запустит новый, пустой процесс с запуском dir, он не будет клонировать какое-либо из текущего состояния процесса. Это единственное соединение с вашей программой - это соединение родитель-ребенок.

Вы видите, fork() - вызов очень низкого уровня. Например, в Linux, что fork() в основном делает это: во-первых, создается новый процесс с точно клонированным регистром. Затем Linux делает ссылку "копирование на запись" на все страницы родительского процесса. Затем Linux клонирует некоторые другие флаги процесса. Очевидно, что все эти операции могут выполняться только ядром, а ядро ​​Windows не имеет возможностей для этого (и не может быть исправлено).

Технически, только родные программы нуждаются в ОС для своего рода поддержки fork(). Любой слой кода требует взаимодействия слоя над ним, чтобы сделать что-то вроде fork(). Поэтому, в то время как родной код C нуждается в сотрудничестве ядра с fork, Ruby теоретически нуждается только в сотрудничестве с интерпретатором, чтобы сделать вилку. Однако интерпретатор Ruby не имеет функции моментального снимка/восстановления, которая была бы обязательно для реализации вилки. Из-за этого обычная вилка Ruby достигается путем разворачивания самого интерпретатора, а не программы Ruby.

Итак, если вы можете исправить интерпретатор Ruby, чтобы добавить функцию stop/start и snapshot/restore, вы можете это сделать, но в противном случае? Я так не думаю.

Итак, каковы ваши варианты? Это то, о чем я могу думать:

  • Исправить интерпретатор Ruby
  • Замените код, который использует fork(), чтобы использовать потоки или нереститься
  • Получить UNIX (я предлагаю этот)
  • Использовать Cygwin

Изменить 1: Я бы не предложил использовать вилку Cygwin, поскольку она включает специальные таблицы процессов Cygwin, существует нет copy-on-write, что делает ее очень неэффективной. Кроме того, он включает в себя много прыжков назад и вперед и много копирования. Избегайте его, если это возможно. Кроме того, поскольку Windows не предоставляет возможности для копирования адресных пространств, вилки с большой вероятностью потерпят неудачу и будут довольно много времени (см. здесь).