15

私の開発環境は、ruby 1.9.3p125(RubyInstaller)とrails3.2.8を実行しているWindowsマシンです。

サードパーティのgemを使用するときに何度も発生する問題の1つは、Windowsにfork()がないことです。これは最近、フォークに依存しているため、ほとんどすべての分散テスト実行gem(これらのような)を使用する能力を妨げています

StackOverflowに関するいくつかの古い質問は、この同じ問題の解決策を見つけようとしましたが、Process.spawnをrubyに追加する前か、他の理由で古いバージョンのRubyを使用せざるを得なかった人々からのものでした。

提案された解決策の1つは、Cygwinを使用してfork()サポートを取得することです。これは、これについては問題外です。その前に、Linuxに完全に切り替えることをお勧めします。

別の提案された解決策は、win32プロセスgemを使用してfork()サポートを取得することです。フォークのサポートは最新バージョン(0.7.0)から削除され、次に古いバージョン(0.6.6)を使用すると、少なくとも分散型のいずれかを実行する場合に、(一種の)フォークのサポートが機能しないようです。私が試した宝石のテスト(Spork、Parallelテスト、Hydra、Specjour、実質的にすべて)。興味深いことに、gemの作成者は、Readmeで、Process.spawnがProcess.forkの許容可能な回避策であることをほのめかしています。

私は多くの情報を暗示しているか、はっきりと述べているのを見てきましたそのスポーンは、WindowsのRuby1.9でフォークの代わりに使用できます。私はこれでかなりの時間を費やしましたが、基本的に、参照されているいくつかのgemでProcess.forkをProcess.spawnに置き換えようとしましたが、成功しませんでした。おそらく動作は似ているように見えますが、まったく同じではありません。たとえば、spawnが実際にフォークと同じ方法でプロセス全体をコピーするのか、それとも単に指定された引数を使用して新しいプロセスを作成するのかは不明です。また、spawnメソッドが別のrubyメソッドを引数として受け入れるのか、それともシステムコマンドのみを受け入れるのかについても不明です。ドキュメントはそれが単なるコマンドであることを暗示しているようですが、メソッドは(一種の)機能しているようですが、私は物事を間違って行っている可能性があります。いくつかの点で、フォークは「安いスレッド」を作成するために使用されただけだと思います。スレッド化をサポートしていなかった以前のrubyバージョン。ただし、これらの分散テストgemは、プロジェクトの状態を維持し、すべてのテストでruby環境全体をロードしないために、fork()の全機能に合法的に依存しているようです。これは私の通常のプログラミングの義務と経験から少し外れているので、私はいくつかの間違った仮定をしているかもしれません。

だから、私の質問は、すべての場合において、Process.spawnを比較的簡単に使用してProcess.forkと同じ結果を達成できるかということです。私はそうは思わないようになりましたが、もしそうなら、誰かが変革を行う方法の例を投稿していただけませんか?

4

1 に答える 1

15

編集:---コンボにfork()置き換えることができる一般的なユースケースが1つあります。多くの古い(そして最新の)UNIXアプリケーションは、別のプロセスを生成したい場合、最初にフォークしてから呼び出しを行います(現在のプロセスを別のプロセスに置き換えます)。これは実際には必要ありません。そのため、に置き換えることができます。したがって、この:spawn()fork()exec()execexecfork()spawn()

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

次のように置き換えることができます:

Process.spawn("dir")

いずれかの宝石がfork()このように使用されている場合、修正は簡単です。そうでなければ、それはほとんど不可能です。


編集:win32-processの実装が機能しない理由fork()は(ドキュメントからわかる限り)、基本的に spawn()、まったく機能fork()しないためです。


いいえ、できないと思います。ご覧のProcess.spawnとおり、デフォルトの空白状態とネイティブコードを使用して新しいプロセスを作成します。したがって、新しい空白のプロセスの実行Process.spawn('dir')を開始するようなことはできますが、現在のプロセスの状態は複製されませんプログラムへの唯一の接続は親-子接続です。dir

ほらfork()、非常に低レベルの呼び出しです。たとえば、Linuxの場合、fork()基本的には次のようになります。最初に、正確に複製されたレジスタ状態で新しいプロセスが作成されます。次に、Linuxはすべての親プロセスのページへのコピーオンライト参照を実行します。次に、Linuxは他のいくつかのプロセスフラグを複製します。明らかに、これらの操作はすべてカーネルによってのみ実行でき、Windowsカーネルにはそれを実行する機能がありません(また、どちらにもパッチを適用することはできません)。

技術的には、ネイティブプログラムだけが何らかのfork()サポートのためにOSを必要とします。コードのどのレイヤーでも、のようなことを行うには、その上のレイヤーの協力が必要ですfork()。したがって、ネイティブCコードはフォークするためにカーネルの協力を必要としますが、Rubyは理論的にはフォークを行うためにインタープリターの協力を必要とするだけです。ただし、Rubyインタープリターにはスナップショット/復元機能がありません。これは必然的にフォークを実装するためのものです。このため、通常のRubyフォークは、Rubyプログラムではなく、インタープリター自体をフォークすることによって実現されます。

したがって、Rubyインタープリターにパッチを適用して、停止/開始およびスナップショット/復元機能を追加できれば、それは可能ですが、そうでない場合はどうでしょうか。私はそうは思わない。

それで、あなたの選択肢は何ですか?これは私が考えることができるものです:

  • Rubyインタープリターにパッチを適用する
  • fork()スレッドまたはスポーンを使用するために使用するコードにパッチを適用します
  • UNIXを入手する(これをお勧めします)
  • Cygwinを使用する

編集1:Cygwinのフォークを使用することはお勧めしません。これには、特別なCygwinプロセステーブルが含まれ、コピーオンライトがないため、非常に非効率的です。また、それは多くの前後のジャンプと多くのコピーを伴います。可能であれば避けてください。また、Windowsにはアドレス空間をコピーする機能がないため、フォークが失敗する可能性が非常に高く、かなりの時間がかかります(ここを参照)。

于 2012-09-07T13:45:57.037 に答える