是否可能在所有PHP进程之间共享变量和数组,而不会复制它们?
使用memcached,我认为PHP会复制所使用的内存:
$array = $memcache->get('array');
$array 将包含来自memcached的副本。
因此,我的想法是,可以有一个已经定义并在所有进程之间共享的静态变量。
是否可能在所有PHP进程之间共享变量和数组,而不会复制它们?
使用memcached,我认为PHP会复制所使用的内存:
$array = $memcache->get('array');
$array 将包含来自memcached的副本。
因此,我的想法是,可以有一个已经定义并在所有进程之间共享的静态变量。
使用 Shmop
:
Shmop 是一组易于使用的函数,允许 PHP 读取、写入、创建和删除 Unix 共享内存段。
来源: http://www.php.net/manual/en/intro.shmop.php
构建此扩展不需要外部库。
共享内存函数
基本用法
// 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);
在PHP进程间共享内存的方法之一是安装一个像APC的PHP-bytecode缓存。APC主要用于将字节码存储到操作系统管理的共享内存段中,但它也有一个API可用于在进程之间共享任何你想要的东西(比如本地版本的memcache)。
<?php
$foobar = array('foo', 'bar');
apc_store('foobar', $foobar);
?>
<?php
$foobar = apc_fetch('foobar');
var_dump($foobar);
?>
Shmop
怎么样?请看下面。 - PacerierPHP有魔术方法:
__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上,您可以在这里找到它。
true
放在变量上时,__get函数找不到我的变量。我发现tmp文件末尾有}}
而不是}
。因此,我添加了fwrite($fd, str_replace('}}','}',json_encode($object)));
,但这是一个我不喜欢的解决方法。 - Melomanshmop_read
时,返回值实际上是共享内存中实际值的副本。您不能通过引用从shmop读取。 shmop的好处是读取和检索性能,在许多情况下与数据库相比可以忽略不计。 - KingCrunch编辑:
你可能在错误的方式下使用共享内存。
你的共享内存本身就是这样一个数组。因此,你必须直接将单独的多语言字符串存储在共享内存中,而不是将它们存储在大数组中。
然后只需要在特定页面上拉取所需的字符串。
就这样。
一般来说,为了处理某些数据,程序必须通过将其存储在变量中来“复制”它。
这就是变量的作用-存储(或“复制”)一些外部数据。
例如,如果你的数据库中有一些用户信息,在网页上显示用户名,你必须首先将这些数据“复制”,将其存储在PHP变量中。
等等。
你是第一个认为这种方法需要改变的人。