Windows 上で Perl CGI スクリプトからバックグラウンド プロセスをフォークするにはどうすればよいですか?
-
09-06-2019 - |
質問
Windows 上で実行しているときに、Perl CGI スクリプトからプロセスをフォークするときに問題が発生しました。主な問題は、Windows 上で実行するときに「fork」がエミュレートされ、実際には新しいプロセス (現在のプロセスの別のスレッド) を作成しているようには見えないことのようです。これは、プロセスの終了を待機している Web サーバー (IIS など) が、「バックグラウンド」プロセスが終了するまで待機し続けることを意味します。
Windows で CGI スクリプトからバックグラウンド プロセスをフォークする方法はありますか?さらに良いのは、これをクロスプラットフォームで実行する単一の関数を呼び出すことができるかということです。
(そして、作業をさらに困難にするために、フォークされたプロセスの出力を同時にファイルにリダイレクトする良い方法が欲しいと思っています)。
解決
これをプラットフォームに依存しない方法で実行したい場合は、 プロセス::バックグラウンド おそらく最良の方法です。
他のヒント
使用 Win32::プロセス -> 作成 DETACHED_PROCESS パラメータあり
Perlは、同じ名前のUNIXシステムコールに対応するFork()キーワードを提供します。Fork()システムコールが利用可能なほとんどのUNIXのようなプラットフォームでは、PerlのFork()が単純に呼び出します。
Fork()システムコールが使用できないWindowsなどの一部のプラットフォームでは、Perlを構築して、通訳レベルでFork()をエミュレートできます。エミュレーションは、PERLプログラムのレベルで実際のfork()と可能な限り互換性があるように設計されていますが、すべての擬似子供「プロセス」がこの方法でライブを作成したという事実に由来する特定の重要な違いがあります。オペレーティングシステムに関する限り、同じ実際のプロセスで。
Windows 上の fork() には、特に Perl で Win32 オブジェクトを扱う場合に大きな問題があることがわかりました。したがって、Windows 固有のものになる場合は、Perl 内の Thread ライブラリを参照することを強くお勧めします。
私はこれを効果的に使用して、IIS を使用する Web サイトで一度に複数の接続を受け入れ、さらに多くのスレッドを使用してさまざまなスクリプトを一度に実行します。
この質問は非常に古いものであり、受け入れられた答えは正しいです。ただし、これが機能するようになったので、それを必要とする人のために、それを実現する方法についてさらに詳細を追加したいと考えました。
次のコードは、非常に大規模な Perl CGI スクリプトに存在します。この特定のサブルーチンは、複数の発券システムでチケットを作成し、返されたチケット番号を使用して Twilio サービス経由で自動呼び出しを行います。呼び出しにはしばらく時間がかかるため、CGI ユーザーが要求の出力を確認するために呼び出しが終了するまで待たされることは望ましくありませんでした。そのために、私は次のことを行いました。
(All the CGI code that is standard stuff. Calls the subroutine needed, and then)
my $randnum = int(rand(100000));
my $callcmd = $progdir_path . "/aoff-caller.pl --uniqueid $uuid --region $region --ticketid $ticketid";
my $daemon = Proc::Daemon->new(
work_dir => $progdir_path,
child_STDOUT => $tmpdir_path . '/stdout.txt',
child_STDERR => $tmpdir_path . '/stderr.txt',
pid_file => $tmpdir_path . '/' . $randnum . '-pid.txt',
exec_command => $callcmd,
);
my $pid = $daemon->Init();
exit 0;
(kill CGI at the appropriate place)
乱数を生成して pid に付加するのはやりすぎだと確信していますが、非常に簡単に回避できる問題を作成することに私は興味がありません。これが同じようなことをしようとしている人の助けになれば幸いです。忘れずに追加してください use Proc::Daemon
スクリプトの先頭でコードをミラーリングし、プログラムのパスと名前を変更すれば準備完了です。