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

问题描述:

是否有可能在所有PHP进程之间共享变量和数组而不复制它们在所有PHP进程之间共享变量/内存

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

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

+1

是你的阵列大吗? – 2011-04-09 14:39:25

+0

是的。你可以添加更多的上下文吗?如何将数据存储在数据库中,并只检索当前脚本中需要的位? – 2011-04-09 15:04:09

+0

这通常是通过将数据存储在数据库中并仅提取所需内容来解决的。 – 2011-04-09 22:43:35

默认情况下它根本不可能。每个解决方案都会将内容复制到当前范围内,因为如果没有,则无法访问它。

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

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

+5

好的,最后一个有用的答案:“不可能”。我比侮辱或讽刺更真诚。谢谢,这是我接受的答案。 – Nuno 2011-04-09 16:47:39

+0

关于你的第三段,我已经用其他的东西来使用这种方法。我担心的是,当我真的不知道会发生什么时,就像我在问题中所说的那样。 – Nuno 2011-04-09 16:49:24

+2

@Nuno不要那么敏感。没有人侮辱你。如果答案对您没有帮助,请尝试改善您的问题,而不是感到受伤。 – 2011-04-09 16:51:20

编辑:
您可能正在使用共享内存错误的方式。
你的共享内存本身就是这样的数组。因此,您必须将独立的多语言字符串直接存储在共享内存中,而不是使用它们的大数组。
然后只拉字符串,在特定页面上需要。这就是全部。

通常,为了处理一些数据,程序必须通过将其存储在一个变量中来“复制”它。
这就是变量的用途 - 存储(或“复制”)一些外部数据。例如,如果在数据库中有一些用户信息,要在网页上显示用户名,则必须“复制”该数据,首先将其存储在PHP变量中。
依此类推。

你是第一个认为这种方法需要改变的人。

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

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

然后在别处:

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

的大问题,共享内存是它变得非常容易了两个进程踩对方的脚。所以共享内存最适合不会变化太大的事情,比如大型全局阵列。

+0

这看起来与Memcached相同。谢谢你的回答,无论如何:) – Nuno 2011-04-09 16:35:50

+1

@NunoPeralta,那么'Shmop'呢?见下文。 – Pacerier 2015-01-19 07:11:03

+0

这是错误的,apc_store等不能在进程之间共享内存。每个进程分配它自己的内存段。你可以不分享php-fpm和php-cli之间的内存(同时在不同的php-fpm请求之间共享)。 – bhelm 2016-07-07 09:15:13

PHP有魔术方法:

  • __get($property)让我们实现一个$属性的对象的访问
  • __set($property, $value)让我们实现一个对象上的$属性的分配

PHP可以序列化变量:

  • serialize($variable)返回变量
  • unserialize($string)返回的字符串表示从字符串返回变量

PHP可以处理文件,并发访问管理:

  • fopen($file, 'c+')打开一个文件,咨询锁定选项启用(允许您使用群)
  • flock($descriptor, LOCK_SH)需要一个共享锁(用于读取)
  • flock($descriptor, LOCK_EX)需要一个e XCLUSIVE锁(用于书面方式)

所以,共享应用程序之间的对象最简单的方法是创建一个类,它实现和使用所有这些东西给它的所有数据保存和瞬间恢复到文件中。

的简单实现类的可能是:现在

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上推了这个类(完成之后),你可以找到它here

+3

你误解了这个问题。 – Pacerier 2015-01-19 07:11:41

+0

喜欢它...使用文件可能是最简单的方式,也是更安全的方式,因为没有尝试服务器的内存。我认为这比问一个数据库要快。 – Meloman 2017-07-07 13:32:14

+0

这与使用数据库没有区别,其思想是共享内存中的变量,而不是磁盘上的变量。 – 2017-11-06 02:52:15

使用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); 
+1

另请参阅http://*.com/a/8631902/632951 – Pacerier 2015-01-19 07:11:21

+1

[要使用shmop,您需要在配置行中使用** - enable-shmop **参数编译PHP。](http:// php.net/manual/en/shmop.installation.php) – Pang 2016-06-27 04:55:54