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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

Q&A

解決済

5回答

8767閲覧

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

Saitoh

総合スコア8

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

0グッド

0クリップ

投稿2015/02/26 01:55

時間のかかる処理を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;

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

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();

}

投稿2015/03/03 01:59

Saitoh

総合スコア8

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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();
}

投稿2015/03/02 05:14

Saitoh

総合スコア8

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

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

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

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

投稿2015/02/26 03:39

munyaX

総合スコア783

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

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

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

先ず、Windowsには fork がないので

lang

1my $pid = fork; 2# forkが失敗した場合はエラー処理を行う 3unless (defined $pid) { 4 die "fork faild."; 5}

は、恐らく無駄でしょう。

バックグラウンドでプロセスを起動するには?

上記にある

lang

1system("cmd &")

が、Windowsでは

lang

1system("start cmd")

にあたります。

Windows環境が手元に無いので試せないので、試せないのが恐縮ですが

lang

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

start のオプションなどでなんとかならないでしょうか。

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

投稿2015/02/26 03:04

編集2015/02/26 03:21
moeru_gomi

総合スコア42

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Saitoh

2015/02/26 03: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");も、試してみましたが、ブラウザの表示はやはりファイル作成後でした。
Saitoh

2015/02/26 05:21

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

0

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

lang

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

投稿2015/02/26 02:13

moeru_gomi

総合スコア42

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Saitoh

2015/02/26 02:23

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

2015/02/26 03: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 &")
Saitoh

2015/03/02 01: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
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問