2011-04-09 68 views
17

是否有可能在所有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

回答

4

默認情況下它根本不可能。每個解決方案都會將內容複製到當前範圍內,因爲如果沒有,則無法訪問它。

我不知道,究竟想要做什麼,但也許你可以做到「外部」,例如作爲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

0

編輯:
您可能正在使用共享內存錯誤的方式。
你的共享內存本身就是這樣的數組。因此,您必須將獨立的多語言字符串直接存儲在共享內存中,而不是使用它們的大數組。
然後只拉字符串,在特定頁面上需要。這就是全部。

通常,爲了處理一些數據,程序必須通過將其存儲在一個變量中來「複製」它。
這就是變量的用途 - 存儲(或「複製」)一些外部數據。例如,如果在數據庫中有一些用戶信息,要在網頁上顯示用戶名,則必須「複製」該數據,首先將其存儲在PHP變量中。
依此類推。

你是第一個認爲這種方法需要改變的人。

7

在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

3

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

18

使用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://stackoverflow.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