Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 共享記憶體實作 PHP 記憶體佇列:SHM + 信號量同步、環狀緩衝區、序列化存儲、多進程安全

編輯:Linux 教學

基於 System V 共享記憶體 (shmop) 與信號量 (sem) 實作高效能、多進程安全的 PHP 記憶體佇列,支援任意資料類型 (透過序列化)。

核心類別設計 SHMQueue

<?php
class SHMQueue {
    private $maxQSize = 0;      // 最大佇列長度 (塊數)
    private $front = 0;         // 隊頭指標 (位元組偏移)
    private $rear = 0;          // 隊尾指標
    private $blockSize = 256;   // 每塊大小 (bytes)
    private $memSize = 25600;   // 共享記憶體總大小 (bytes)
    private $shmId = 0;         // shmop handle
    private $filePtr = './shmq.ptr'; // 持久化指標檔
    private $semId = 0;         // 信號量 ID

    public function __construct() {
        $shmKey = ftok(__FILE__, 't');
        $this->shmId = shmop_open($shmKey, "c", 0644, $this->memSize);
        $this->maxQSize = $this->memSize / $this->blockSize;

        $this->semId = sem_get($shmKey, 1);
        sem_acquire($this->semId);          // 進入臨界區
        $this->init();                      // 還原指標
    }

    private function init() {
        if (file_exists($this->filePtr)) {
            list($this->front, $this->rear) = explode('|', file_get_contents($this->filePtr)) + [0,0];
        }
    }

    public function getLength() {
        return (($this->rear - $this->front + $this->memSize) % $this->memSize) / $this->blockSize;
    }

    public function enQueue($value) {
        if ($this->ptrInc($this->rear) == $this->front) return false; // 滿
        $data = $this->encode($value);
        shmop_write($this->shmId, $data, $this->rear);
        $this->rear = $this->ptrInc($this->rear);
        return true;
    }

    public function deQueue() {
        if ($this->front == $this->rear) return false; // 空
        $value = shmop_read($this->shmId, $this->front, $this->blockSize - 1);
        $this->front = $this->ptrInc($this->front);
        return $this->decode($value);
    }

    private function ptrInc($ptr) {
        return ($ptr + $this->blockSize) % $this->memSize;
    }

    private function encode($value) {
        $data = serialize($value) . "__eof";
        if (strlen($data) > $this->blockSize - 1)
            throw new Exception("Data size " . strlen($data) . " exceeds block size!");
        return $data;
    }

    private function decode($value) {
        return unserialize(explode("__eof", $value)[0]);
    }

    public function __destruct() {
        file_put_contents($this->filePtr, "$this->front|$this->rear");
        sem_release($this->semId);          // 離開臨界區
    }
}

使用範例

// 生產者
$q = new SHMQueue();
$q->enQueue(['task_id' => 123, 'payload' => 'data']);
unset($q);  // 釋放鎖、持久化指標

// 消費者
$q = new SHMQueue();
$task = $q->deQueue();
unset($q);

關鍵設計亮點

  1. 環狀緩衝區:ptrInc 取模實現循環,無需資料搬移。
  2. 固定塊大小:256B/塊,簡化位移計算;超大資料需自行分片或增大 blockSize。
  3. 信號量保護:sem_acquire/release 確保多進程並發安全 (PHP 預設無線程安全)。
  4. 指標持久化:__destruct 寫入檔案,進程重啟後可恢復佇列狀態。
  5. 序列化邊界標記:__eof 分隔符配合 serialize/unserialize 支援任意類型。

避坑與擴展建議

  • 塊大小調整:根據業務平均物件大小設定,避免內部碎片浪費或溢出拋異常。
  • 共享記憶體總量:受限於 kernel.shmmax、kernel.shmall 系統參數,大佇列需調整 /etc/sysctl.conf。
  • 信號量洩漏:異常退出未釋放鎖會導致死鎖,建議註冊 register_shutdown_function 強制 sem_release。
  • 高效能替代:Redis List/Stream、Disruptor 模式 (PHP 無原生)、Swoole Channel/Table 更適合高併發場景。
Copyright © Windows教程網 All Rights Reserved