質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.22%

CGI で時間のかかる処理をbackgroundで実行したい

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 4,092

Saitoh

score 8

時間のかかる処理をbackgroundで処理して、ブラウザ上は終了させたいのですが、うまく子プロセスが動いてくれません。Windowsだからでしょうか?

Windows 7
IIS 7.5
StrawberryPerl 5.18.4

test.cgi

use strict;
use warnings;
use utf8;

print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "システムコマンド実行\n";

my $pid = fork;
# forkが失敗した場合はエラー処理を行う
unless (defined $pid) {
    die "fork faild.";
}
close STDIN;
close STDOUT;
close STDERR;

# 子プロセスは以下を実行
if ($pid == 0) {
    system( "perl C:/inetpub/wwwroot/data/script/test_001.pl" );
}

exit(0);


------------ test_001.pl
use strict;
use warnings;
use utf8;

$| = 1;
open TST, "> ./testtest.log";
foreach (1..30) {
    print TST $_ . "\n";
    sleep(1);
}
close TST;
exit;
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

0

コメントにしようとして失敗しました。すいません。

時間のかかる処理をbackgroundで処理して、ブラウザ上は終了させたいのですが、うまく子プロセスが動いてくれません。Windowsだからでしょうか?

先ず、Windowsには fork がないので
my $pid = fork; 
# forkが失敗した場合はエラー処理を行う 
unless (defined $pid) { 
    die "fork faild."; 
} 
は、恐らく無駄でしょう。

バックグラウンドでプロセスを起動するには?
上記にある
system("cmd &")
が、Windowsでは
system("start cmd")
にあたります。

Windows環境が手元に無いので試せないので、試せないのが恐縮ですが
system("start", "perl C:/inetpub/wwwroot/data/script/test_001.pl");
や start のオプションなどでなんとかならないでしょうか。

あとは、動かないと言うのがどういう風に動かないのかが気になります。
動かないと仰っているのは、test_001.pl の実行結果を待ってしまうと言う事でしょうか?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/02/26 12:39

    「動かない」=test_001.pl で作成されるべきファイルが作成されてない。ということです。
    わかりにくくて申し訳ありません。

    system( "start", "perl C:/inetpub/wwwroot/data/script/test_001.pl" );
    上記を実行したところ、ファイル作成なし&test.cgiによる表示もなしの状態になりました。
    system("start perl C:/inetpub/wwwroot/data/script/test_001.pl");とは違う動きになったので、
    system("start", "perl", "C:/inetpub/wwwroot/data/script/test_001.pl");も、試してみましたが、ブラウザの表示はやはりファイル作成後でした。

    キャンセル

  • 2015/02/26 14:21

    system( "start", "/b", "perl", "C:/inetpub/wwwroot/data/script/test_001.pl", "/c" );
    を実行してみましたが、やはり
    ファイルの作成終了までブラウザでの表示はされず(ファイル作成終了を待ってからブラウザ表示)という結果になりました。
    ただしブラウザ(該当CGIのタグ)を終了させた後も、ファイルは作成されましたので、うまく使えないかなぁ。と。この辺で手打ちにしようかと。
    Windowsでの限界かも…。
    何度も回答していただき、ほんとうにありがとうございました。

    キャンセル

0

start を使ってみてはいかがでしょう。

system("start perl C:/inetpub/wwwroot/data/script/test_001.pl");

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/02/26 11:23

    試してみたのですが、動いてくれませんでした。

    英語で同様の問いに対し、Proc::Background というモジュール使え的な回答があったので、いま試しにインストールしてコードを書いていますが、英語が苦手なために半分あきらめ気味です。
    上記のモジュールをちょっと試してみます。

    キャンセル

  • キャンセル

  • 2015/02/26 12:30

    test.cgiで
    use Proc::Background;
    my $command = "perl";
    my $arg1 = "test_001.pl";
    my $proc1 = Proc::Background->new( $command, $arg1);

    # プロセスがいきてるなら
    if ($proc1->alive) {
    exit;
    }
    としてみましたが、終わるまで待ち状態に。
    いろいろ試してみましたが、「test_001.plがうまく動く」=「プロセス終わるまで待つ」がセットになってしまいます。

    これが使えたら・・・。
    >>
    Unix 風のシステムを使っているなら、コマンドの最後に & を置くことで システムコールから切り離すことができるかもしれません:
    system("cmd &")

    キャンセル

  • 2015/03/02 10:21

    あれから結局タスクスケジューラを1日1回batで動かすことで対応することになりました。
    ただ、なんだかあきらめきれずに色々あさってみました。
    http://chaichan.lolipop.jp/qa6500/qa6720.htm を参考にして、
    use threads; を使うと、もしかしたらうまく動くかなぁ、と思ってtryしてみたのですが、今度はコマンドプロンプトで起動したとたん、エラーウィンドウが表示されてしまいました。
    endoceは使ってないので、なぜなのか。不明ですが、やはり無理そうです。

    perl interpreter は動作を停止しました
    問題イベント名 APPCRASH
    アプリケーション名 perl.exe
    アプリケーションのバージョン  5.18.4.1
    アプリケーションのタイムスタンプ 542d2726
    障害モジュールの名前  encoding.dll
    障害モジュールのバージョン 0.0.0.0
    障害モジュールのタイムスタンプ 542d2843
    例外コード  c0000005
    例外オフセット00003727
    OSバージョン 6.1.7.601.2.1.0.256.48
    ロケーるID 1041

    キャンセル

0

ご質問の内容と少しずれますが、
UNIX系OSでいうcron、Windowsならタスクスケジューラが利用できるのであれば、以下のような方法もあります。

  1.  データファイルに実行内容(タスク)を記録
  2.  cronでデータファイルを読み込んで実行内容にそって実行

例えば
・Aさんがアクセス→データファイルには1を記録
・Bさんがアクセス→データファイルには2を記録
・cronでデータファイルを読み込んで2回実行する
といった感じです。
(実際にデータファイルには1行ずつ追記していく形が多いですかね)


この方法の利点は、大量にリクエストがあった場合でも重たい(時間のかかる)処理が一度に大量に走らない点です。ご参考まで。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

以下のコードを実行したところ、コマンドプロンプト上では期待通りの動き(出力即終了&その後もファイル作成)ができましたが、ブラウザ上では無理でした。おそらくIISの設定的な問題かもしれません。ありがとうございました。

use Thread;
$| = 1;
my $thread1 = Thread->new(\&thre1, "1"); 
my $thread2 = Thread->new(\&thre2);

$thread1->join;

$thread2->detach;
my $result = $thread2->is_detached();
if ($thread2->is_running()) {
    sleep(1);
}

sub thre1() { 
   my ($name) = @_;
   print "Content-Type: text/html; charset=Shift_JIS\n\n";
   print "testtest<br><br>\n\n";
   for (1..50) { 
       print "$name ($_)<br>\n"; 
   } 
   yield(); 
}

sub thre2() { 
    my @arg = qw( perl C:/inetpub/wwwroot/data/script/test_001.pl );
    my @res = system ("start", "/B", @arg );
    yield();

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

下記のコードで、perl.exe が、2つ起動したのをタスクマネージャーで確認し、コマンドプロンプトでは期待通りの動き(表示は即終了し、2つ目のプロセスが他の処理)をしたのですが、ブラウザを介するとなぜか全てのプロセスの終了が完了するまで、ブラウザで表示してくれませんでした。Perlは悪くないのかもしれず、もしかしたらIISの設定が何か必要なのかもしれません。

------

use Thread;
$| = 1;
my $thread1 = Thread->new(\&thre1, "1"); 
my $thread2 = Thread->new(\&thre2, "2");

$thread1->join;
$thread2->detach;
if ($thread2->is_running()) {
    sleep(1);
}

my $result = $thread2->is_detached();
print "result:$result";

sub thre1() { 
   my ($name) = @_;
   print "Content-Type: text/html; charset=Shift_JIS\n\n";
   print "testtest<br><br>\n\n";
   for (1..50) { 
       print "$name ($_)<br>\n"; 
   } 
   threads->yield(); 
}

sub thre2() { 

    my @arg = qw( perl C:/inetpub/wwwroot/data/script/test.pl );
    my @res = system ("start", "/B", @arg );
    threads->yield();


投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる