在所有PHP进程之间共享变量/内存

Nun*_*uno 19 php shared-memory

是否可以在所有PHP进程之间共享变量和数组而不重复它们

使用memcached,我认为PHP重复使用的内存:
$array = $memcache->get('array');
$ array将包含memcached的副本.

所以我的想法是,可能有一个已定义的静态变量,并在所有进程之间共享.

Raf*_*shi 21

使用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);
Run Code Online (Sandbox Code Playgroud)

  • [要使用 shmop,您需要在配置行中使用 **--enable-shmop** 参数编译 PHP。](http://php.net/manual/en/shmop.installation.php) (2认同)

wm_*_*die 8

在PHP进程之间共享内存的一种方法是安装像APC这样的PHP字节码缓存.APC主要用于将字节码存储到OS管理的共享内存段中,但它还具有用于在进程之间共享任何内容的API(如本地版本的memcache).

<?php
   $foobar = array('foo', 'bar');
   apc_store('foobar', $foobar);
?>
Run Code Online (Sandbox Code Playgroud)

其他地方:

<?php
    $foobar = apc_fetch('foobar');
    var_dump($foobar);
?>
Run Code Online (Sandbox Code Playgroud)

共享内存的一个大问题是两个进程很容易互相踩踏.因此共享内存最适合那些不会发生太大变化的事情,比如大型全局数组.

  • 这是错误的,apc_store等不能在进程之间共享内存。每个进程分配自己的内存段。因此,您可以不在 php-fpm 和 php-cli 之间共享内存(而在不同的 php-fpm 请求之间共享内存)。 (4认同)

Ala*_*blo 5

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;
   }

}
Run Code Online (Sandbox Code Playgroud)

现在,您可以像使用此类stdClass,但在构造时使用文件路径。

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

// ... and in another process...
echo $obj->hello;
Run Code Online (Sandbox Code Playgroud)

这个例子当然很简单,它关心并发访问文件而不是变量,在更好的实现中,您将使用类似互斥锁的锁。

我刚刚在github上推送了该类(完成后),您可以在这里找到它。

  • 您误解了这个问题。 (5认同)
  • 这与使用数据库没有什么不同,其想法是共享内存中的变量,而不是磁盘上的变量。 (3认同)

Kin*_*nch 3

默认情况下这是不可能的。每个解决方案总是会将内容复制到当前作用域中,因为如果没有,则无法访问它。

我不知道,到底想做什么,但也许你可以在“外部”做,例如作为齿轮工工作,然后只捕获过程的结果,而不是整个数组。

您还可以考虑将“大”数组拆分为多个切片,然后始终从 apc 或 memcached 检索当前需要的部分。