12

PECLpthreadThreadは配列オブジェクトを使用できないことがわかりました。原因を見つけるために何ができますか?

コード例:

   class my extends Thread {

           public function __construct() {
                   $this->arr = array();
                   $this->id  = 0;
           }
           public function run() {
                   while (true) {
                           $this->wait();
                   }
           }

           public function add() {
                   $this->id = rand(0, 1000);
                   $this->arr[] = rand(0, 1000);
                   var_dump($this->id);//this is rand
                   var_dump($this->arr);//this is empty array()
                   $this->notify();
           }
   }

   $my = new my();
   $my->start();
   while (true) {
           sleep(1);
           $my->add();
   } 
4

1 に答える 1

37

問題

PHPはシェアードナッシング環境です。つまり、各プロセス(またはスレッド)には、インタープリター、すべてのモジュール、およびユーザーコードの独自のコピーが必要です。

HashTablePHP配列をサポートするだけでなく、PHPコードベース全体で使用される構造は、複数のコンテキストで操作されることを意図したものではありませんでした。

配列の新しいメンバーを設定する(mallocと同等)、設定を解除する(freeと同等)、または更新する(freeとmallocと同等)たびに呼び出されるメモリマネージャーは、シェアードナッシングの不可欠な部分です。アーキテクチャ、およびとりわけ、これはシェアードナッシングの違反を構成するため、別のコンテキストによって割り当てられたメモリを解放するコンテキストを禁止するように特別に設計されています。

仮想マシンは、それがアレイを操作する唯一のコンテキストであると想定しています。

すべての拡張コードは同じ仮定をします。

ルールを無視すること(何も共有しないこと)の結果は悲惨です:あなたはPHPをクラッシュさせます。

これらすべてにより、実際の配列を複数のコンテキストで格納および操作できるようになり、実現不可能になり、望ましくないものになるはずです。

PHP5

配列は、オブジェクトのメンバーとして設定するとシリアル化されThreadedます。

Threaded配列の使用法をオブジェクトに置き換える必要があります。

Threadedオブジェクトは、配列であるのように操作できます。

これがあなたが始めるための何かです:

<?php
class Test extends Thread {
    public function __construct(Threaded $storage) {
        $this->storage = $storage; 
    }

    public function run(){
        $i = 0;
        while(++$i < 10) {
            $this->storage[]=rand(0,1000);
        }

        $this->synchronized(function($thread){
            $thread->stored = true;
            $thread->notify();
        }, $this);
    } 
}

$storage = new Threaded();
$my = new Test($storage);
$my->start();

$my->synchronized(function(Thread $thread){
    while (!$thread->stored) {
        $thread->wait();
    }
}, $my);

var_dump($storage);
?>

PHP7

pthreads v3(PHP7)は、Threadedオブジェクトの自動不変性の概念を導入しています。

pthreadsv3の不変性に関する私のブログ投稿からの引用:

pthreads v3では、Threadedオブジェクトのメンバー(A)を別のThreadedオブジェクト(B )に設定すると、 AがBに対して保持する参照が不変になります。

不変性はパフォーマンスの最適化です。

明らかに、配列のほとんどのユースケースには、配列の変更が含まれますが、Threadedオブジェクトが常にサポートできるとは限りません。

この特定のケースでは、Threaded配列のメンバーはどれもThreadedです。

pthreads v3(PHP7)は、Volatileオブジェクトの概念を導入しています。

揮発性形容詞:特に悪化した場合、急速かつ予測不可能に変化する傾向があります。

VolatileThreadedオブジェクトは、不変性によって可能になるパフォーマンスの最適化の恩恵を受けることができないため、オブジェクトよりも低速です。

Volatileオブジェクトは、pthreadsv3の配列の優れた代替手段として機能します。pthreadは、オブジェクトがオブジェクトVolatileのメンバーとして設定されている場合、配列をオブジェクトに強制変換しThreadedます。

<?php
class Test extends Thread {
    public function run(){
        $array = [
            "Hello",
            "World"
        ];

        var_dump($array);

        $this->array = $array;

        var_dump($this->array);
    } 
}

$test = new Test();
$test->start() && $test->join();
?>

降伏します:

array(2) {
  [0]=>
  string(5) "Hello"
  [1]=>
  string(5) "World"
}
object(Volatile)#2 (2) {
  [0]=>
  string(5) "Hello"
  [1]=>
  string(5) "World"
}

これにより$this->array、の実行時に期待どおりに動作しますThread

次のコードの出力で示される副作用があります。

<?php
class Test extends Thread {
    public function __construct(array $array) {
        $this->array = $array;
    }

    public function run(){
        var_dump($this->array);
    } 
}

$array = [
    "Hello",
    "World"
];
$test = new Test($array);
$test->start() && $test->join();
var_dump($array);
?>

降伏します:

object(Volatile)#2 (2) {
  [0]=>
  string(5) "Hello"
  [1]=>
  string(5) "World"
}
array(2) {
  [0]=>
  string(5) "Hello"
  [1]=>
  string(5) "World"
}

Volatileのオブジェクトは、そのコンストラクターに提供されたオブジェクトThreadから切断されてarrayいるため、メインコンテキストは引き続きを操作していることに注意してくださいarray

Thread自動強制は、別のソースから渡された配列を操作するときに、1分あたりのwtfsレートを下げるのに役立ちます。

明示的である方が常に良いです。強制に頼らないのが最善の選択肢です。

一部の依存関係が配列になることがすでにわかっている場合は、それらをメンバーとして設定する前に対処し、強制を完全に回避します。

Volatile明示的なキャストを使用することにより、への自動強制を回避することができます。

<?php
class Test extends Thread {
    public function run() {
        $this->result = (array) [
            "Hello" => "World"
        ];
    }
}

$test = new Test();
$test->start() && $test->join();
var_dump($test->result);
?>

降伏します

array(1) {
  ["Hello"]=>
  string(5) "World"
}

サンプルコードが示すように、これは、実際に配列を使用して結果を格納する場合に役立ちます。PHP5と同様に、配列はストレージ用にシリアル化されます。

于 2013-02-10T17:12:29.523 に答える