web-dev-qa-db-ja.com

すべてのPHPプロセス間で変数/メモリを共有する

すべてのPHPプロセスそれらを複製せずに間で変数と配列を共有することは可能ですか?

Memcachedを使用すると、PHPは使用済みメモリを複製すると思います:
$array = $memcache->get('array');
$ arrayには、memcachedからのコピーが含まれます。

つまり、私の考えでは、すでに定義され、すべてのプロセス間で共有されているstatic変数が存在する可能性があります。

19
Nuno

デフォルトでは、それは単に不可能です。すべてのソリューションは常にコンテンツを現在のスコープにコピーします。そうでない場合、コンテンツにアクセスする方法がないためです。

正確に何をしたいのかわかりませんが、たとえば gearman ジョブとして「外部」で実行し、配列全体ではなく、プロセスの結果を取得することができます。

また、「大きな」配列をスライスに分割して、現在必要な部分をapcまたはmemcachedから常に取得することも考えられます。

3
KingCrunch

Shmopの使用:

Shmopは、PHPがUnix共有メモリセグメントの読み取り、書き込み、作成、および削除を可能にする、使いやすい関数のセットです。

差出人: http://www.php.net/manual/en/intro.shmop.php

この拡張機能を構築するために外部ライブラリは必要ありません。

共有メモリ関数

  • shmop_close —閉じる
  • 共有メモリブロック
  • shmop_delete —共有メモリブロックを削除します
  • shmop_open —共有メモリブロックを作成または開く
  • shmop_read —共有メモリブロックからデータを読み取ります
  • shmop_size —共有メモリブロックのサイズを取得します
  • shmop_write —共有メモリブロックにデータを書き込みます

基本的な使用法

// Create 100 byte shared memory block with system id of 0xff3
$shm_id = shmop_open(0xff3, "c", 0644, 100);
if (!$shm_id) {
    echo "Couldn't create shared memory segment\n";
}

// Get shared memory block's size
$shm_size = shmop_size($shm_id);
echo "SHM Block Size: " . $shm_size . " has been created.\n";

// Lets write a test string into shared memory
$shm_bytes_written = shmop_write($shm_id, "my shared memory block", 0);
if ($shm_bytes_written != strlen("my shared memory block")) {
    echo "Couldn't write the entire length of data\n";
}

// Now lets read the string back
$my_string = shmop_read($shm_id, 0, $shm_size);
if (!$my_string) {
    echo "Couldn't read from shared memory block\n";
}
echo "The data inside shared memory was: " . $my_string . "\n";

//Now lets delete the block and close the shared memory segment
if (!shmop_delete($shm_id)) {
    echo "Couldn't mark shared memory block for deletion.";
}
shmop_close($shm_id);
21
RafaSashi

PHPプロセス間でメモリを共有する1つの方法は、 [〜#〜] apc [〜#〜] のようなPHPバイトコードキャッシュをインストールすることです。APCは主に次の目的で使用されます。バイトコードをOS管理の共有メモリセグメントに格納しますが、プロセス間で必要なものを共有するためのAPIもあります(ローカルバージョンのmemcacheなど)。

<?php
   $foobar = array('foo', 'bar');
   apc_store('foobar', $foobar);
?>

その後、他の場所:

<?php
    $foobar = apc_fetch('foobar');
    var_dump($foobar);
?>

共有メモリの大きな問題は、2つのプロセスがお互いの足を踏むのが非常に簡単になることです。したがって、共有メモリは、大きなグローバルアレイなど、あまり変更されないものに最適です。

8
wm_eddie

PHPには魔法のメソッドがあります:

  • __get($property)オブジェクトへの$ propertyのアクセスを実装しましょう
  • __set($property, $value)オブジェクトに$ propertyの割り当てを実装しましょう

PHPは変数をシリアル化できます。

  • serialize($variable)は変数の文字列表現を返します
  • unserialize($string)は文字列から変数を返します

PHPは、同時アクセス管理を使用してファイルを処理できます。

  • fopen($file, 'c+')は、アドバイザリロックオプションが有効になっているファイルを開きます(flockを使用できるようにします)
  • flock($descriptor, LOCK_SH)は共有ロックを取得します(読み取り用)
  • flock($descriptor, LOCK_EX)は排他ロックを取ります(書き込み用)

したがって、アプリ間でオブジェクトを共有する最も簡単な方法は、これらすべてのものを実装および使用して、すべてのデータをファイルに即座に保存および復元するクラスを作成することです。

そのクラスの簡単な実装は次のようになります。

class Synchro
{

   private $_file;

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

   public function __get($property)
   {
       // File does not exist
       if (!is_file($this->_file))
       {
           return null;
       }

       // Check if file is readable
       if ((is_file($this->_file)) && (!is_readable($this->_file)))
       {
           throw new Exception(sprintf("File '%s' is not readable.", $this->_file));
       }

       // Open file with advisory lock option enabled for reading and writting
       if (($fd = fopen($this->_file, 'c+')) === false)
       {
           throw new Exception(sprintf("Can't open '%s' file.", $this->_file));
       }

       // Request a lock for reading (hangs until lock is granted successfully)
       if (flock($fd, LOCK_SH) === false)
       {
           throw new Exception(sprintf("Can't lock '%s' file for reading.", $this->_file));
       }

       // A hand-made file_get_contents
       $contents = '';
       while (($read = fread($fd, 32 * 1024)) !== '')
       {
           $contents .= $read;
       }

       // Release shared lock and close file
       flock($fd, LOCK_UN);
       fclose($fd);

       // Restore shared data object and return requested property
       $object = json_decode($contents);
       if (property_exists($object, $property))
       {
           return $object->{$property};
       }

       return null;
   }

   public function __set($property, $value)
   {
       // Check if directory is writable if file does not exist
       if ((!is_file($this->_file)) && (!is_writable(dirname($this->_file))))
       {
           throw new Exception(sprintf("Directory '%s' does not exist or is not writable.", dirname($this->_file)));
       }

       // Check if file is writable if it exists
       if ((is_file($this->_file)) && (!is_writable($this->_file)))
       {
           throw new Exception(sprintf("File '%s' is not writable.", $this->_file));
       }

       // Open file with advisory lock option enabled for reading and writting
       if (($fd = fopen($this->_file, 'c+')) === false)
       {
           throw new Exception(sprintf("Can't open '%s' file.", $this->_file));
       }

       // Request a lock for writting (hangs until lock is granted successfully)
       if (flock($fd, LOCK_EX) === false)
       {
           throw new Exception(sprintf("Can't lock '%s' file for writing.", $this->_file));
       }

       // A hand-made file_get_contents
       $contents = '';
       while (($read = fread($fd, 32 * 1024)) !== '')
       {
           $contents .= $read;
       }

       // Restore shared data object and set value for desired property
       if (empty($contents))
       {
           $object = new stdClass();
       }
       else
       {
           $object = json_decode($contents);
       }
       $object->{$property} = $value;

       // Go back at the beginning of file
       rewind($fd);

       // Truncate file
       ftruncate($fd, strlen($contents));

       // Save shared data object to the file
       fwrite($fd, json_encode($object));

       // Release exclusive lock and close file
       flock($fd, LOCK_UN);
       fclose($fd);

       return $value;
   }

}

これで、このクラスをstdClassのように使用できますが、構築時にファイルパスを使用できます。

$obj = new Synchro("/tmp/test.sync"); 
$obj->hello = 'world';

// ... and in another process...
echo $obj->hello;

この例はもちろん非常に単純で、変数へのアクセスではなくファイルへの同時アクセスを処理します。より良い実装では、ミューテックスのようなロックを使用します。

このクラスを(完了後に)githubにプッシュしたところ、見つけることができます ここ

5
Alain Tiemblo

編集:
共有メモリを間違った方法で使用している可能性があります。
共有メモリ自体がそのような配列です。したがって、個別の多言語文字列を共有メモリに直接格納する必要があります。大きな配列ではありません。
次に、特定のページで必要な文字列のみをプルします。
それで全部です。

一般に、一部のデータを処理するには、プログラムはデータを変数に格納することによってデータを「複製」する必要があります。
それが変数の目的です-外部データを保存(または「複製」)します。
たとえば、データベースにユーザー情報がある場合、Webページにユーザー名を表示するには、このデータを「複製」して、PHP変数を最初に格納する)必要があります。 。
等々。

あなたはそのようなアプローチを変える必要があると最初に考える人です。

0