467

PHP でマルチスレッド モデルを実装する現実的な方法はありますか? しばらく前に、オペレーティング システムに強制的に PHP 実行可能ファイルの別のインスタンスをロードさせ、他の同時プロセスを処理させることができると提案されました。

これの問題は、PHP コードの実行が終了しても、PHP インスタンスを PHP 内から強制終了する方法がないため、PHP インスタンスがメモリ内に残ることです。したがって、複数のスレッドをシミュレートしている場合、何が起こるか想像できます。そのため、PHP 内から効果的にマルチスレッドを実行またはシミュレートできる方法をまだ探しています。何か案は?

4

15 に答える 15

484

PHPでマルチスレッドが可能

はい、 pthreadsを使用して PHP でマルチスレッドを実行できます

PHPドキュメントから:

pthreads は、PHP でのマルチスレッドに必要なすべてのツールを提供するオブジェクト指向 API です。PHP アプリケーションは、スレッド、ワーカー、およびスレッド化されたオブジェクトを作成、読み取り、書き込み、実行、および同期できます。

警告: pthreads 拡張機能は Web サーバー環境では使用できません。したがって、PHP でのスレッド化は、CLI ベースのアプリケーションのみにとどめるべきです。

簡単なテスト

#!/usr/bin/php
<?php
class AsyncOperation extends Thread {

    public function __construct($arg) {
        $this->arg = $arg;
    }

    public function run() {
        if ($this->arg) {
            $sleep = mt_rand(1, 10);
            printf('%s: %s  -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep);
            sleep($sleep);
            printf('%s: %s  -finish' . "\n", date("g:i:sa"), $this->arg);
        }
    }
}

// Create a array
$stack = array();

//Initiate Multiple Thread
foreach ( range("A", "D") as $i ) {
    $stack[] = new AsyncOperation($i);
}

// Start The Threads
foreach ( $stack as $t ) {
    $t->start();
}

?>

ファーストラン

12:00:06pm:     A  -start -sleeps 5
12:00:06pm:     B  -start -sleeps 3
12:00:06pm:     C  -start -sleeps 10
12:00:06pm:     D  -start -sleeps 2
12:00:08pm:     D  -finish
12:00:09pm:     B  -finish
12:00:11pm:     A  -finish
12:00:16pm:     C  -finish

セカンドラン

12:01:36pm:     A  -start -sleeps 6
12:01:36pm:     B  -start -sleeps 1
12:01:36pm:     C  -start -sleeps 2
12:01:36pm:     D  -start -sleeps 1
12:01:37pm:     B  -finish
12:01:37pm:     D  -finish
12:01:38pm:     C  -finish
12:01:42pm:     A  -finish

実際の例

error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
    public $url;
    public $data;

    public function __construct($url) {
        $this->url = $url;
    }

    public function run() {
        if (($url = $this->url)) {
            /*
             * If a large amount of data is being requested, you might want to
             * fsockopen and read using usleep in between reads
             */
            $this->data = file_get_contents($url);
        } else
            printf("Thread #%lu was not provided a URL\n", $this->getThreadId());
    }
}

$t = microtime(true);
$g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10));
/* starting synchronization */
if ($g->start()) {
    printf("Request took %f seconds to start ", microtime(true) - $t);
    while ( $g->isRunning() ) {
        echo ".";
        usleep(100);
    }
    if ($g->join()) {
        printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data));
    } else
        printf(" and %f seconds to finish, request failed\n", microtime(true) - $t);
}
于 2013-03-19T13:55:02.653 に答える
58

なぜpopenを使わないのですか?

for ($i=0; $i<10; $i++) {
    // open ten processes
    for ($j = 0; $j < 10; $j++) {
        $pipe[$j] = popen('script2.php', 'w');
    }

    // wait for them to finish
    for ($j = 0; $j < 10; ++$j) {
        pclose($pipe[$j]);
    }
}
于 2010-12-03T22:27:03.310 に答える
27

スレッド化は標準のPHPでは使用できませんが、非同期呼び出しとしてHTTP要求を使用することにより、並行プログラミングが可能です。

curlのタイムアウト設定を1に設定し、相互に関連付けたいプロセスに同じsession_idを使用すると、以下の例のようにセッション変数と通信できます。この方法を使用すると、ブラウザーを閉じることもでき、並行プロセスはサーバー上にまだ存在します。

次のように正しいセッションIDを確認することを忘れないでください。

http://localhost/test/verifysession.php?sessionid=[正しいID]

startprocess.php

$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];

process1.php

set_time_limit(0);

if ($_REQUEST["sessionid"])
   session_id($_REQUEST["sessionid"]);

function checkclose()
{
   global $_SESSION;
   if ($_SESSION["closesession"])
   {
       unset($_SESSION["closesession"]);
       die();
   }
}

while(!$close)
{
   session_start();
   $_SESSION["test"] = rand();
   checkclose();
   session_write_close();
   sleep(5);
}

verifysession.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
var_dump($_SESSION);

closeprocess.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);
于 2009-07-03T14:31:49.187 に答える
17

スレッド化はできませんが、php である程度のプロセス制御を行うことができます。ここで役立つ 2 つの関数セットは次のとおりです。

プロセス制御機能 http://www.php.net/manual/en/ref.pcntl.php

POSIX 関数 http://www.php.net/manual/en/ref.posix.php

子プロセスの PID を返す pcntl_fork でプロセスをフォークできます。次に、posix_kill を使用してその PID を破棄できます。

そうは言っても、親プロセスを強制終了すると、子プロセスにシグナルを送信して、子プロセスを終了するように指示する必要があります。php 自体がこれを認識しない場合は、それを管理する関数を登録し、pcntl_signal を使用してクリーンな終了を行うことができます。

于 2008-09-16T10:30:11.473 に答える
12

これは古い質問であることは知っていますが、探している人のために、PHPマルチスレッド機能を提供するCで書かれたPECL拡張機能があり、ここにありますhttps://github.com/krakjoe/pthreads

于 2012-09-19T02:39:12.057 に答える
9

exec() を使用してコマンド ライン スクリプト (コマンド ライン php など) を実行できます。出力をファイルにパイプすると、スクリプトはコマンドが終了するまで待機しません。

php CLI 構文をよく思い出せませんが、次のようなものが必要です。

exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");

セキュリティ上の理由から、かなりの数の共有ホスティング サーバーで exec() がデフォルトで無効になっていると思いますが、試してみる価値があるかもしれません。

于 2008-09-16T14:03:11.103 に答える
6

次のオプションがあります。

  1. multi_curl
  2. 同じためにシステムコマンドを使用することができます
  3. 理想的なシナリオは、C言語でスレッド関数を作成し、PHPでコンパイル/構成することです。これで、その関数はPHPの関数になります。
于 2011-05-10T07:40:26.270 に答える
6

How about pcntl_fork?

check our the manual page for examples: PHP pcntl_fork

<?php

    $pid = pcntl_fork();
    if ($pid == -1) {
        die('could not fork');
    } else if ($pid) {
        // we are the parent
        pcntl_wait($status); //Protect against Zombie children
    } else {
        // we are the child
    }

?>
于 2012-01-13T00:55:28.300 に答える
6

Linux サーバーを使用している場合は、

exec("nohup $php_path path/script.php > /dev/null 2>/dev/null &")

いくつかの引数を渡す必要がある場合

exec("nohup $php_path path/script.php $args > /dev/null 2>/dev/null &")

script.php で

$args = $argv[1];

または、Symfony https://symfony.com/doc/current/components/process.htmlを使用します

$process = Process::fromShellCommandline("php ".base_path('script.php'));
$process->setTimeout(0);     
$process->disableOutput();     
$process->start();
于 2020-04-29T15:12:25.620 に答える
5

スレッドをシミュレートできます。PHPは、popen(またはproc_open)を介してバックグラウンドプロセスを実行できます。これらのプロセスは、stdinおよびstdoutを介して通信できます。もちろん、これらのプロセス自体をphpプログラムにすることもできます。それはおそらくあなたが得るのと同じくらい近いでしょう。

于 2010-08-26T21:33:57.870 に答える
5

何をしようとしているのかによっては、curl_multi を使用してそれを達成することもできます。

于 2011-01-25T04:45:09.980 に答える
4

pcntl_forkセーフ モードがオンになっている場合、Web サーバー環境では動作しません。この場合、PHP の CLI バージョンでのみ機能します。

于 2012-02-02T04:07:04.687 に答える
-3

マルチスレッドとは、複数のタスクまたはプロセスを同時に実行することを意味します。PHP でこれを実現するには、次のコードを使用します。ただし、PHP でマルチスレッドを実現する直接的な方法はありませんが、次の方法でほぼ同じ結果を得ることができます。

chdir(dirname(__FILE__));  //if you want to run this file as cron job
 for ($i = 0; $i < 2; $i += 1){
 exec("php test_1.php $i > test.txt &");
 //this will execute test_1.php and will leave this process executing in the background and will go         

 //to next iteration of the loop immediately without waiting the completion of the script in the   

 //test_1.php , $i  is passed as argument .

}

Test_1.php

$conn=mysql_connect($host,$user,$pass);
$db=mysql_select_db($db);
$i = $argv[1];  //this is the argument passed from index.php file
for($j = 0;$j<5000; $j ++)
{
mysql_query("insert  into  test   set

                id='$i',

                comment='test',

                datetime=NOW() ");

}

これにより、test_1.php が同時に 2 回実行され、両方のプロセスが同時にバックグラウンドで実行されるため、この方法で php でマルチスレッドを実現できます。

この男は本当に良い仕事 をしました PHP でのマルチスレッド化

于 2013-11-05T12:51:26.120 に答える