• ベストアンサー

CGIの処理中に次の処理が出来る?

perlで書いたCGIの処理時間が非常に長いのです。 処理は数百名に対してメールを配信するもので、テキストで書かれた数百のメールアドレス配列に対してループ文で一人ずつメールを配信しています。これが約4分くらいかかります。 質問は2つあって、 (1)まずこのメール配信の処理を早くする方法はないでしょうか?  配信アドレスは自動的に追加されたり削除されたりするので固定のML  を使う事ができませんので、個別にメールを送る方法を取っていま  す。 (2)メール配信をバックグランドで実行させて、メインのプログラムは  復帰させる、という方法が出来るでしょうか?  今は、メインCGIが画面の表示やメールの配信などほとんどを実行し  ています。  このような場合、メール配信中はそのメインCGIが実行権を握った  状態になる為、他のユーザはこのメインCGIを実行出来ないと思って  いるのですが、間違った認識でしょうか?  もしそうだとすると、早くメインCGIの実行権を他のユーザに明け渡 さなければならないと思うので、メール配信を別CGIで実行させたほ うが良いのかな?と思った次第です。  よろしくご教示下さい。

  • CGI
  • 回答数3
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
  • galluda
  • ベストアンサー率35% (440/1242)
回答No.3

がると申します。 1番については「処理次第」としか言いようがないのですが。#1さんの補足質問のコードを見てる限りですと「普通はこんなもん」だと思うです。 ここから速度アップを考えると、smtp関連で結構突っ込んだコードになってくるので、「業務的に必須」とか「やる気が両手からあふれかえっている」とかでなければ、このままでよいように思うです。 ちなみに、$mailfile を読み込む際の flock(OUT,8); は不要です。 # flockの解除は「しない」癖をつけたほうが安全です。 んで。 私は「まとめて送信」には比較的懐疑的です。 一つには、ユーザ的に「メールヘッダのToが自分のアドレスである」ほうが好感度が高いのが一つ。 もう一つが、まとめて送るときはSMTP的に「RCPT TO」とうコマンドを列挙するのですが、これには数量限界がありまして。RFC的にもさほど多くない上に(ちょっと記憶に浅いのですが、たしか100~200程度)、実装上ではさらに低い上限(たしか10~20くらい)もありまして。そのあたりから考えるに、まとめての送信はちょっと微妙です。 2番についてですが。 forkなどで別プロセスをたたき起こすことによって「バックグラウンドでの実行」は可能です。ただ、厳密にはforkで作った子プロセスには2パターンの挙動がありまして。さらにHTTPdの挙動も微妙で。 まずforkの子プロセス周りですが。「子プロセスが実行中に親プロセスが終了。子プロセス君、君はどうする?」と質問すると、「んじゃぁ親プロセスのもう一つ上(大抵はプロセスID 0のプロセス)と親子関係結びなおしてそのまま実行」という独立心旺盛な場合と「親が死んだんだもの、僕も一緒に~」という情愛豊かに終了してしまう場合とがあります。 次にHTTPdですが「親プロセスしか監視しない」タイプと「そこから派生した全てのプロセスをチェック」するタイプがやはり存在します。 ですので、可能か不可能かは「環境次第」になってしまいます。 環境に依存しないためには、 ・CGIで「メール送信依頼」をどこか(ファイルまたはDB)に設定する ・cronで定期的に送信依頼をチェック、依頼があれば遂行する というほうがより安全です。 ちなみに「メール配信中はそのメインCGIが実行権を握った状態になる為、他のユーザはこのメインCGIを実行出来ない」ってのは明確に誤りです。 細かく書くと長くなるので省略しますが、基本的にプログラムは「あちこちから呼ばれてパラレルに動くことが可能」です。そのあたりはプロセスとかその辺を勉強すると色々わかると思います。 以上、なにか参考にでもなれば幸いです。

zicojapan
質問者

補足

がるさんありがとうございます。 >私は「まとめて送信」には比較的懐疑的です。 >一つには、ユーザ的に「メールヘッダのToが自分のアドレスである」 >ほうが好感度が高いのが一つ。 ↑の件については、まさにその通りで、だからこそ、1通ずつメールを配信する事で、ユーザには個別にメールが配信さるようにしています。 でも時間が掛かってしまっているのが現状の悩み。(T_T) そこで、Aruku-20030515さんの言われている1回で送信できて、送信先に他のメールアドレスが載らない(個別送信)方法を是非アドバイス頂きたいと思った次第です。 flockの件、アドバイス頂きましてありがとうございます。 (2)については難しい(私にはまだ)内容ですね。勉強させてもらいます。 (1)の1回で送信で実現できないかに望みをかけたいのですが。。。

その他の回答 (2)

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.2

(1) 送信するメールの内容が同一であれば、宛先が可変であっても、1回の送信で全員に送信できます。 ループ処理で1通づつ個別に送信するのは、サーバーに負荷を与え、場合によってはサーバー管理者から該当CGIの使用を禁止される場合があるので、改善必須だと思われます。 (2) WEBサーバーから起動されるCGIは、1セッションにつき1つ起動されます。つまり、2つのクライアントがほぼ同時にセッションを開始すると、CGIは個別に2つ動きます。 言い換えれば「どんなに長い処理をしようが、他のユーザーが待たされる事は無く、待たされるのはCGIを呼び出したユーザーのみ」です。 つまり、実行権の明渡しは考えなくて良いのです。実行権の明渡しなどのマルチタスク処理はOSが勝手に行います。と言うか、実行権を1つのタスクで占有する方が遥かに難しいです。 ここで重要になるのが「CGIがアクセスする資源がセッションごとにユニークではない場合」の処理です。例えば、メールの通し番号を記憶しているファイルなどがそれに該当します。 以下のような処理が2つ同時に動いたらどうなるか考えてみて下さい。 1.連番ファイルから番号(例えば10)を取り出す。 2.番号に1を加えて11にする。 3.連番ファイルに更新した番号11を書き出す。 4.メールに「11」との連番を付けて送信 2人のユーザーが個別に処理を呼び出すなら問題は起きないですが、殆ど同時に呼び出すと以下のように変な事になります。 1-A.連番ファイルから番号(例えば10)を取り出す。 2-A.番号に1を加えて11にする。 1-B.連番ファイルから番号(例えば10)を取り出す。 3-A.連番ファイルに更新した番号11を書き出す。 2-B.番号に1を加えて11にする。 4-A.メールに「11」との連番を付けて送信。 3-B.連番ファイルに更新した番号11を書き出す。 4-B.メールに「11」との連番を付けて送信。 このように、同じ番号のメールが2つ送信されてしまいます。この例は単純な連番処理ですが、配信先アドレスリストにも同様な事が言えます。 Aさんがアドレス削除中に、Bさんがアドレスを追加すると、Aさんのアドレスが削除されずに残ったり、Bさんのアドレスが追加されずに消えたりします。 これを防ぐには、該当ファイルに対して排他処理をしなければなりませんが、ここが非常に難しいのです。排他制御でロックを掛けたままCGIがエラーで終ると、ロック解除する人が居なくなり、永久にロックされる状態になります。また、複数のセッションがお互いをロックし合い、どちらも先に進む事ができずにデットロック状態に陥るのを防ぐ必要も出て来ます。 その為、このような排他制御が必要な共有データを処理する場合、そのような面倒な部分を全部自動的にやってくれる「データベースエンジン」を使うのです。 多数のユーザーが頻繁にアクセスし、しかも、同時にアクセスされる可能性のあるCGIを安定的に動作させるのは、かなり難しいです。頑張って下さい。

zicojapan
質問者

補足

はい、(1)については送信する内容は全て同じです。 是非、1回で送信できる方法をもう少し詳しくアドバイス頂ければ大変助かります。 (2)の例については分かりやすく理解できました。が、排他処理についてはよく考えないと難しそうですね。^_^; こちらはもっと勉強してみます。 何卒(1)の実現案をアドバイスして下さい。m(__)m よろしくお願いします。

回答No.1

1については 適切に処理させれば「一度の送信」で処理できますよ。 (当然、あて先に他人のメイルアドレスが載る事はないです) 2.シェルを適切に処理させていれば当然 その他の処理は動作可能ですよ どういうコードを書いているのか不明なので これ以上は分かりません

zicojapan
質問者

補足

さっそくの回答ありがとうございます。 (1)に関して、是非アドバイス頂きたいと思います。 メール送信のプログラムは以下のように書いています。 注)$mailfile:メールアドレスが書かれたテキストファイル $Title:メールのサブジェクト $message:メール本文 if(!open(OUT,"$mailfile")){&error(err_file);} flock(OUT,2); @MAILDATA = <OUT>; flock(OUT,8); close(OUT); $count_mail = @MAILDATA; if($count_mail > 0){ $i = 0; foreach $line(@MAILDATA){ ($mailaddress,$mail_name) = split(/\,/,$line); open(MAIL, "|$send -t -f '$myaddress'"); print(MAIL "From: AAA <$myaddress>\n"); print(MAIL "To: <$mailaddress>\n"); print MAIL "Subject: $Title\n\n"; print MAIL $message; close(MAIL); $i ++; } } 上記のプログラムだと、$mailfileを1行ずつ読み込んで、一人ずつメールを配信する事になります。従ってメールの配信リスト分のループが発生して時間がかかっています。 これを、一度の送信で処理できる方法をアドバイス頂けますでしょうか? よろしくお願い致します。

関連するQ&A

  • CGIから別サーバーのCGIの呼び出し

    以下の二つのサーバーでCGIを動作させようと考えています。  サーバーA:ユーザーからアクセスできる。  サーバーB:サーバーAからアクセスでき、ユーザーからはアクセスできない。 この環境で (1)サーバーAでリクエストを受け、簡単な処理をする。 (2)サーバーA上のCGIからサーバーB上のCGIを呼び出す。 (3)サーバーB上で処理(etc. メールの送信)を行い、処理結果をサーバーAのCGIに返す。 (4)サーバーA上で簡単な処理を行い、結果をユーザーに表示する というような処理を考えています。 perlでは、このような処理を実装することは可能でしょうか? サーバーAからサーバーBにあるスクリプトファイルを読み込んで、サーバーAで実行するということはできそうなのですが、サーバーB上のCGIはサーバーBで実行するというようなことができるのかがわかりません。 初心者的な質問で申し訳ありませんが、よろしくお願いします。

    • ベストアンサー
    • CGI
  • メルマガ配信のCGIを使うには・・・

    知人の店が独自ドメインでHPを持っているのですが、サーバがCGI不可なのです。 でも独自ドメインのアドレスでメルマガを配信したい、と。 なので、CGI自体は僕のレンサバに置いて、メールアドレスは彼の店のもの、という方法を思いついたのですが、そのようなことは出来るのでしょうか? メルマガ配信のCGIは設置は(もちろん同じサーバで)やったことあるのですが、根本が分かっていないので、なんだかこんがらがってしまって・・・。 かなり馬鹿な質問かもしれませんが、可能か不可能かだけでも教えて下さい。 よろしくお願いします。

  • 2つのプロセスを実行するCGI

    1つのCGIで2つのプロセスを実行することを考えています。 1つは、数分かかるような処理を行い、もう1つはユーザにその処理が”実行中”であるといったメッセージを表示しようと思っています。 CGIはC&C++で作成しようと考えており、forkして子プロセスで、数分かかる処理を実行し、親プロセスでメッセージ画面表示といった流れを考えています。 で、質問ですが、この場合、メッセージ画面で子プロセスが実行している間、砂時計が表示され続けますが、これを消す方法がありますでしょうか? また、1つのCGIで、このように2つのプロセスを実行する場合に、何か良い方法はありますでしょうか?

    • 締切済み
    • CGI
  • Apacheでcgi-binを隠すには

    Apacheの設定でcgiの実行ディレクトリをcgi-binに限定(DocumentRootでのcgi実行は不可)した場合、 アドレスはhttp://hoge.hoge/cgi-bin/となりますが、 これをhttp://hoge.hoge/で実行しているかのように隠蔽(偽装)する方法はないでしょうか?

  • バックグラウンドにて処理を行う方法

    アプリケーション削除時にバックグラウンドにて処理をさせる方法についてお知恵を拝借ください。 端末にインストールされているYahooツールバーを削除する方法を探しています。 別質問(http://okwave.jp/kotaeru.php3?q=2059564)にて 下記レジストリキーを実行することで削除する方法は確立できましたが、 この方法であればアンインストールウィザードが表示されてしまいます。 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\UninstallString] [rundll32.exe C:\PROGRA~1\Yahoo!\COMPAN~1\Installs\YCOMP5~1.DLL,DllCommand ui] バックグラウンドにて処理を行い、ユーザー作業が発生しないことを考えています。 バッチ処理をバックグラウンドで実行させる方法はございませんでしょうか。お知恵を拝借ください。

  • JavaScriptでcgiの戻り値を受け取るには?

    JavaScriptの関数内でcgiを実行(submit)しています。 そのcgiの実行結果(cgiで記述しているexit 0などの0)を受け取る方法を教えてください。 受け取った値によって、alertでメッセージを表示させたいです。 cgiの実行からalertでメッセージを表示させるまでの処理を JavaScriptの1つの関数内で行いたいです。 よろしくお願いいたします。

  • for ( … ){}の処理ができません

    いままで正常に動いていた cgi(perl)に次のようなセンテンス for ( $cnt=0 ; $cnt<2 ; $cnt++) { my $before = "snow06b.gif"; #変換前の名前 my $after = "snow06x.gif"; #変換後の名前 rename($before,$after); my $before = "snow06x.gif"; #変換前の名前 my $after = "snow06b.gif"; #変換後の名前 rename($before,$after); } を追加したところ、cgi 全体が動かなくなってしまいました。 for ( … ){  } の中の処理はこの cgi の他の箇所でも行っていて、正常に実行されることが分かっています。中の処理をはずして for ( $cnt=0 ; $cnt<2 ; $cnt++) { } だけにしてもこの cgi の他の処理を実行しなくなります。自分のパソコンの中にある他のperl のプログラムの中のループの処理と見比べてもどこが悪いのか分かりません。何が原因なのかお教え願えれば幸いです。 初歩的な質問で申し訳ありません。

    • ベストアンサー
    • Perl
  • cgiで呼び出したプログラムを数分後killする

    cgiで呼び出したプログラム(延々と実行します)を、 指定した時間後にkillするcgiを作りたいです。 ここでプロセスidはすでにわかっており、 killコマンドは使えます(linuxを自分で立ち上げてるので) というか、chmod 4755にしておくので 指定する時間はformから受け取るつもりです。 時間は数分、数時間単位、もしくは数日単位です。 あと、formからメールアドレスを受け取って、 プロセスをkillしたあと、その処理結果を受け取ったメールアドレスに送信もしたいです。 メールサーバは立ち上げています。 質問ばかりですいません。 お知恵を拝借させてくださいm(__)m

    • ベストアンサー
    • CGI
  • CGIの起動が遅い

    Web上から作成したCGIを起動した場合に、そのCGIが存在するサーバ上ではすぐに実行されるのですが、他のPCからサーバにアクセスしてCGIを起動するとブラウザの下部にCGI実行中のメッセージが表示されてから結果が表示されるまでに時間がかかっています。(約30-60秒) 他のネットワーク処理等は普通に実行できるので特にネットワークが重い等の問題はないと思うのですが何が問題なのかアドバイスをお願いします。 サーバOSはRedHat Linux 5.1、apacheはver2.2です。

    • 締切済み
    • CGI
  • CGIでメール送信がしたい

    ホームページからメールを出すCGIを作ろうとしています。 コマンドからCGIを直接実行すると問題なく動くのですが、formから動かすと Premature end of script headers: ・・・・ というエラーがでます。いろいろ探してみたんですが、分かりませんでした。 改行コードは端末からviで書いてますので、問題は無いだろうと思っているんですが… エラーはでますが、メールは送っているようです。 コマンドから実行した場合の差出人はroot@hoge.netになっているんですが、 ページから実行させたものはanonymous@hoge.netになります。 きっと勉強不足でとんでもないことをやっているんだろうと思うのですが、 探した範囲には答えがありませんでした。 どこが悪いのか教えてください。よろしくお願いします。 サーバーはVine2.6R1でApacheを使っています。 (test.html) <html> <body> <form name="down" action="/cgi-bin/test/a.cgi" method="post"> <input size="20" type="text" name="a_sel"> <input type="submit"> </body> </html> (a.cgi) #!/usr/bin/perl require '../mimew.pl'; require '../jcode.pl'; $sendmail = "/var/qmail/bin/sendmail"; $master_id = "ho\@hoge.net"; $msg="メッセージ"; &jcode'convert(*msg,'jis'); open (ML,"| $sendmail $master_id"); print ML $msg; close(ML); exit;

    • ベストアンサー
    • CGI