87

完了までに長い時間 (5 ~ 30 分) かかる PHP スクリプトがあります。念のため、スクリプトは curl を使用して別のサーバーからデータをスクレイピングしています。これが、時間がかかる理由です。各ページがロードされるのを待ってから、処理して次のページに移動する必要があります。

スクリプトを開始して、データベース テーブルにフラグを設定するまでそのままにしておく必要があります。

私が知る必要があるのは、スクリプトの実行が完了する前に http 要求を終了できるようにする方法です。また、phpスクリプトはこれを行うための最良の方法ですか?

4

16 に答える 16

119

確かに PHP で実行できますが、これをバックグラウンド タスクとして実行しないでください。新しいプロセスは、それが開始されたプロセス グループから分離する必要があります。

人々はこの FAQ に対して同じように間違った答えを出し続けているので、ここに完全な答えを書きました:

http://symcbean.blogspot.com/2010/02/php-and-long-running-processes.html

コメントから:

短いバージョンですshell_exec('echo /usr/bin/php -q longThing.php | at now');が、「なぜ」という理由は、ここに含めるには少し長いです。

于 2010-02-06T23:35:39.757 に答える
11

手っ取り早い方法はignore_user_abort、php で関数を使用することです。これは基本的に、「ユーザーが何をしようと気にせず、このスクリプトを完了するまで実行してください」と言っています。これは、公開されているサイトの場合、やや危険です (スクリプトが 20 回開始されると、20++ バージョンのスクリプトが同時に実行される可能性があるため)。

「クリーンな」方法(少なくともIMHO)は、プロセスを開始し、1時間ごと(またはそれくらい)にcronjobを実行して、そのフラグが設定されているかどうかを確認するときに、(たとえばdbに)フラグを設定することです。設定されている場合、長期実行スクリプトが開始されます。設定されていない場合、何も起こりません。

于 2010-02-06T09:26:53.613 に答える
8

execまたはsystemを使用してバックグラウンド ジョブを開始し、その中で作業を行うことができます。

また、使用している Web をスクレイピングするためのより良い方法があります。スレッド化されたアプローチ (一度に 1 ページを処理する複数のスレッド) を使用することも、イベントループ (一度に複数のページを処理する 1 つのスレッド) を使用するアプローチを使用することもできます。Perl を使用する私の個人的なアプローチは、AnyEvent::HTTPを使用することです。

ETA: symcbeanは、ここでバックグラウンド プロセスを適切にデタッチする方法を説明しました。

于 2010-02-06T09:49:55.837 に答える
5

いいえ、PHP は最適なソリューションではありません。

Ruby や Perl についてはわかりませんが、Python を使用すると、ページ スクレイパーをマルチスレッドに書き換えることができ、おそらく少なくとも 20 倍高速に実行されるでしょう。マルチスレッド アプリを作成するのは少し難しいかもしれませんが、私が最初に作成した Python アプリはマルチスレッド ページ スクレーパーでした。また、シェル実行関数の 1 つを使用して、PHP ページ内から Python スクリプトを簡単に呼び出すことができます。

于 2010-02-06T09:35:51.573 に答える
3

PHP は最適なツールである場合もあれば、そうでない場合もありますが、使用方法を知っていれば、アプリケーションの残りの部分はそれを使用して作成されます。これらの 2 つの性質は、PHP が「十分に優れている」という事実と相まって、Perl、Ruby、または Python の代わりに PHP を使用することを強く主張しています。

あなたの目標が別の言語を学ぶことである場合は、いずれかを選択して使用してください。あなたが言及したどの言語でも問題なく機能します。私はたまたま Perl が好きですが、あなたの好きなものは違うかもしれません。

Symcbean は、彼のリンクでバックグラウンド プロセスを管理する方法についていくつかの良いアドバイスを提供しています。

つまり、長いビットを処理する CLI PHP スクリプトを作成します。何らかの方法でステータスを報告することを確認してください。AJAX または従来の方法を使用して、ステータスの更新を処理する php ページを作成します。キックオフ スクリプトは、独自のセッションで実行中のプロセスを開始し、プロセスが進行中であることを示す確認を返します。

幸運を。

于 2010-02-08T06:28:55.450 に答える
1

symcbean とは少し異なるソリューションを提案したいと思います。これは主に、長時間実行されるプロセスを apache / www-data ユーザーとしてではなく、別のユーザーとして実行する必要があるという追加の要件があるためです。

cron を使用してバックグラウンド タスク テーブルをポーリングする最初のソリューション:

  • PHP Web ページがバックグラウンド タスク テーブルに挿入され、'SUBMITTED' 状態になる
  • cron は 3 分ごとに 1 回実行され、別のユーザーを使用して、「SUBMITTED」行のバックグラウンド タスク テーブルをチェックする PHP CLI スクリプトを実行します。
  • PHP CLI は、行の状態列を「PROCESSING」に更新して処理を開始し、完了後に「COMPLETED」に更新します

Linux inotify 機能を使用した 2 番目のソリューション:

  • PHP Web ページは、ユーザーが設定したパラメーターを使用して制御ファイルを更新し、タスク ID も提供します。
  • inotifywait を実行するシェル スクリプト (非 www ユーザーとして) は、制御ファイルが書き込まれるのを待ちます。
  • 制御ファイルが書き込まれた後、close_write イベントが発生し、シェル スクリプトが続行されます
  • シェル スクリプトは PHP CLI を実行して長時間実行されるプロセスを実行します。
  • PHP CLI は、タスク ID で識別されるログ ファイルに出力を書き込むか、ステータス テーブルの進行状況を更新します。
  • PHP Web ページは、(タスク ID に基づいて) ログ ファイルをポーリングして、長時間実行されているプロセスの進行状況を表示したり、ステータス テーブルをクエリしたりすることもできます。

いくつかの追加情報は私の投稿にあります: http://inventorsparadox.blogspot.co.id/2016/01/long-running-process-in-linux-using-php.html

于 2016-01-31T12:32:25.993 に答える
1

XHR (Ajax) リクエストとして送信できます。通常の HTTP リクエストとは異なり、クライアントには通常、XHR のタイムアウトはありません。

于 2010-02-06T23:51:28.473 に答える
1

これはバックグラウンド プロセスで実行する必要があるという回答に同意します。しかし、作業が完了していることをユーザーが認識できるように、ステータスを報告することも重要です。

プロセスを開始するための PHP リクエストを受け取ったときに、一意の識別子を使用してタスクの表現をデータベースに保存できます。次に、スクリーン スクレイピング プロセスを開始し、一意の識別子を渡します。タスクが開始されたこと、および最新のステータスを取得するために、新しいタスク ID を含む指定された URL を確認する必要があることを iPhone アプリに報告します。iPhone アプリケーションは、この URL をポーリング (または「ロング ポーリング」) できるようになりました。その間、バックグラウンド プロセスは、完了率、現在のステップ、またはその他の必要なステータス インジケーターを使用して、タスクのデータベース表現を更新します。終了すると、完了フラグが設定されます。

于 2010-02-06T19:58:59.103 に答える
0

Perl、ダブル fork()、および親プロセスからのデタッチで同様のことを行いました。すべての http 取得作業は、フォークされたプロセスで実行する必要があります。

于 2010-02-06T19:41:36.533 に答える
0

プロキシを使用してリクエストを委任します。

于 2010-10-29T22:17:03.617 に答える
0

長いスクリプトがある場合は、各タスクの入力パラメーターの助けを借りてページ作業を分割します(その後、各ページはスレッドのように機能します)。つまり、ページに1つのlac product_keywords長いプロセスループがある場合、ループの代わりに1つのキーワードのロジックを作成し、このキーワードを渡しますmagic または cornjobpage.php から (次の例)

バックグラウンド ワーカーの場合は、この手法を試してみるべきだと思います。好きなだけページを呼び出すと、すべてのページが非同期として各ページの応答を待たずに一度に独立して実行されます。

cornjobpage.php //メインページ

    <?php

post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue");
//post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue2");
//post_async("http://localhost/projectname/otherpage.php", "Keywordname=anyValue");
//call as many as pages you like all pages will run at once independently without waiting for each page response as asynchronous.
            ?>
            <?php

            /*
             * Executes a PHP page asynchronously so the current page does not have to wait for it to     finish running.
             *  
             */
            function post_async($url,$params)
            {

                $post_string = $params;

                $parts=parse_url($url);

                $fp = fsockopen($parts['host'],
                    isset($parts['port'])?$parts['port']:80,
                    $errno, $errstr, 30);

                $out = "GET ".$parts['path']."?$post_string"." HTTP/1.1\r\n";//you can use POST instead of GET if you like
                $out.= "Host: ".$parts['host']."\r\n";
                $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
                $out.= "Content-Length: ".strlen($post_string)."\r\n";
                $out.= "Connection: Close\r\n\r\n";
                fwrite($fp, $out);
                fclose($fp);
            }
            ?>

testpage.php

    <?
    echo $_REQUEST["Keywordname"];//case1 Output > testValue
    ?>

PS: URL パラメータをループとして送信する場合は、次の回答に従ってください: https://stackoverflow.com/a/41225209/6295712

于 2016-12-19T15:32:26.220 に答える
0

私が常に使用しているのは、これらのバリアントの1つです(Linuxのフレーバーが異なると、出力の処理に関するルールが異なります/一部のプログラムの出力が異なるため)。

バリアント I @exec('./myscript.php \1>/dev/null \2>/dev/null &');

バリアント II @exec('php -f myscript.php \1>/dev/null \2>/dev/null &');

バリアント III @exec('nohup myscript.php \1>/dev/null \2>/dev/null &');

「nohup」をインストールしていない可能性があります。しかし、たとえば、FFMPEG ビデオ変換を自動化していたとき、出力ストリーム 1 と 2 をリダイレクトすることによって出力インターフェイスが 100% 処理されなかったので、nohup を使用して出力をリダイレクトしました。

于 2011-09-07T10:42:47.483 に答える
0

スクリプトの目的の出力が Web ページではなく何らかの処理である場合、目的の解決策はシェルからスクリプトを実行することだと思います。

php my_script.php

于 2019-09-13T09:35:43.617 に答える