Совместное использование переменных / памяти между всеми процессами PHP - PullRequest
18 голосов
/ 09 апреля 2011

Можно ли совместно использовать переменные и массивы между всеми процессами PHP , не дублируя их ?

Используя memcached, я думаю, что PHP дублирует используемую память:
$array = $memcache->get('array');
$ array будет содержать копию из memcached.

Итак, моя идея в том, что может существовать статическая переменная, которая уже была определена и распределена между всеми процессами.

Ответы [ 5 ]

20 голосов
/ 20 мая 2014

Использование Shmop:

Shmop - это простой в использовании набор функций, который позволяет PHP читать, писать, создавать и удалять сегменты общей памяти Unix.

from: 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);
8 голосов
/ 09 апреля 2011

Одним из способов разделения памяти между процессами PHP является установка кэша байт-кода PHP, например APC . APC в основном используется для хранения байт-кода в управляемом ОС сегменте совместно используемой памяти, но также имеет API для совместного использования всего, что вам нужно, между процессами (например, локальной версией memcache).

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

Тогда в другом месте:

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

Большая проблема с разделением памяти состоит в том, что двум процессам становится очень легко наступать друг другу на ноги. Поэтому общая память лучше всего подходит для вещей, которые не сильно меняются, например, для больших глобальных массивов.

4 голосов
/ 29 мая 2013

В PHP есть магические методы:

  • __get($property) давайте реализуем доступ к свойству $ для объекта
  • __set($property, $value) давайте реализуем присвоение свойства $для объекта

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, вы можете найти его здесь .

3 голосов
/ 09 апреля 2011

По умолчанию это просто невозможно.Каждое решение всегда будет копировать контент в текущую область, потому что если нет, то нет способа получить к нему доступ.

Я не знаю, что именно нужно делать, но, возможно, вы можете сделать это «снаружи»например, как gearman задание, а затем просто поймать результаты процесса, а не весь массив.всегда извлекайте нужную вам часть из apc или memcached.

0 голосов
/ 09 апреля 2011

Edit:
Возможно, вы неправильно используете общую память.
Ваша общая память сама по себе является таким массивом. Таким образом, вы должны хранить отдельных многоязычных строк непосредственно в общей памяти, а не в большом массиве с ними.
а затем только тянуть строки, необходимые на конкретной странице.
это все.

Как правило, для обработки некоторых данных программе необходимо «продублировать» их, сохранив в переменной.
Вот для чего нужны переменные - для хранения (или «дублирования») некоторых внешних данных.
Например, если у вас есть некоторая информация о пользователе в вашей базе данных, чтобы отобразить имя пользователя на веб-странице, вы должны «продублировать» эти данные, предварительно сохранив их в переменной PHP.
И так далее.

Вы первый, кто считает, что такой подход необходимо изменить.

...