2024 日本 PHP 研討會

基本用法

範例 #1 共享記憶體操作概觀

<?php

// 建立一個 100 位元組的共享記憶體區塊,系統 ID 為 0xff3
$shm_id = shmop_open(0xff3, "c", 0644, 100);
if (!
$shm_id) {
echo
"無法建立共享記憶體區段\n";
}

// 取得共享記憶體區塊的大小
$shm_size = shmop_size($shm_id);
echo
"已建立共享記憶體區塊大小: " . $shm_size . " 位元組\n";

// 將測試字串寫入共享記憶體
$shm_bytes_written = shmop_write($shm_id, "my shared memory block", 0);
if (
$shm_bytes_written != strlen("my shared memory block")) {
echo
"無法寫入完整資料長度\n";
}

// 讀取字串
$my_string = shmop_read($shm_id, 0, $shm_size);
if (!
$my_string) {
echo
"無法從共享記憶體區塊讀取資料\n";
}
echo
"共享記憶體中的資料為: " . $my_string . "\n";

// 刪除區塊並關閉共享記憶體區段
if (!shmop_delete($shm_id)) {
echo
"無法標記共享記憶體區塊以進行刪除。";
}
shmop_close($shm_id);

?>

新增註解

使用者貢獻的註解 1 則註解

匿名
6 年前
用於 SHMOP 實作的簡單類別。

# 警告 #

您只能單向讀寫。如果您嘗試同時讀寫,您將會得到損毀的資料。(它的運作方式類似標準輸入/輸出)
如果您需要雙向通訊,請建立兩個 shmop 類別的實例。
對於同一個 shmid,請勿嘗試附加多個讀取器或寫入器,否則會造成資料損毀。此類別使用了一些權宜的 spinlocks 來提升速度,並未使用真正的原子操作。您可以使用 flock 加入信號量,但速度會非常慢(約為原本的 1/3)。

效能基準測試

每秒讀取次數:6316 每秒資料大小:6.17 GB

<?php
########################
# shmopwriter.php
########################

$blockSize = 1024 * 1024 * 100;
$data = random_bytes($blockSize);

try
{
$shm = new SHMOP('shmopwriter.php', 'c', 644, $blockSize);

while(
1)
{
if(!
$shm->canWrite())
continue;

$shm->write($data);
}

$shm->close();

} catch (
Exception $e) {
echo
'Error: ', $e->getMessage(), PHP_EOL;
exit;
}

########################

########################
# shmopreader.php
########################

$blockSize = 1024 * 1024 * 100;
$shm = new SHMOP('shmopwriter.php', 'c', 644, $blockSize);
$readsMT = 0;
$readsPS = 0;

while(!
$shm->eof())
{
$times = microtime(true);

if((
$data = $shm->read()) === false)
continue;

$readsPS++;
$readsMT += round(((microtime(true) - $times ) * 1000), 3);

if(
$readsMT > 1000)
{
echo
'Reads per sec: ', $readsPS, ' Data size per sec: ', convert($blockSize * $readsPS), PHP_EOL;
$readsPS = 0;
$readsMT = 0;
}
}

function
convert($size)
{
$unit=array('b','kb','mb','gb','tb','pb');
return @
round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
}
########################

########################
# shmop.class.php
########################

class SHMOP
{
private
$shmId;
private
$shmHeaderSize;
private
$shmHeaderOffset;
private
$shmBlockSize;
private
$shmMaxBlockSize;

function
__construct(string $pathname, string $flags, int $mode, int $size)
{
$this->shmHeaderSize = strlen($size);
$this->shmHeaderOffset = $this->shmHeaderSize + 1;
$this->shmMaxBlockSize = $size;
$this->shmBlockSize = $size + $this->shmHeaderOffset + 1;

$this->shmId = shmop_open(ftok($pathname, 's'), $flags, $mode, $this->shmBlockSize);

if(!
$this->shmId)
throw new
Exception('shmop_open error');
}

function
__destruct()
{
if(!
$this->shmId)
return;

$this->close();
}

public function
read()
{
// Check SpinLock
if(shmop_read($this->shmId, 0, 1) === "\0")
return
false;

// Get Header
$dataSize = (int)shmop_read($this->shmId, 1, $this->shmHeaderSize);

$data = shmop_read($this->shmId, $this->shmHeaderOffset, $dataSize);
// release spinlock
shmop_write($this->shmId, "\0", 0);
return
$data;
}

public function
write(string $data)
{
// Check SpinLock
if(shmop_read($this->shmId, 0, 1) !== "\0")
return
false;

$dataSize = strlen($data);

if(
$dataSize < 1)
throw new
Exception('dataSize < 1');

if(
$dataSize > $this->shmMaxBlockSize)
throw new
Exception('dataSize > shmMaxBlockSize: '. $this->shmMaxBlockSize);

// pack very slow use kludge
$dataSize .= "\0";

// Write Header
shmop_write($this->shmId, $dataSize, 1);
// Write Data
shmop_write($this->shmId, $data, $this->shmHeaderOffset);
// Write spinlock
shmop_write($this->shmId, "\1", 0);
return
true;
}

public function
eof()
{
return (
shmop_read($this->shmId, 0, 1) === "\2") ? true : false;
}

public function
sendeof()
{
// Check SpinLock
if(shmop_read($this->shmId, 0, 1) !== "\0")
return
false;

shmop_write($this->shmId, "\2", 0);
return
true;
}

public function
canWrite()
{
// Check SpinLock
return (shmop_read($this->shmId, 0, 1) === "\0") ? true : false;
}

public function
close()
{
return @
shmop_close($this->shmId);
}

private function
delete()
{
$del = @shmop_delete($this->shmId);

if(
$del === false)
return
false;

return @
shmop_close($this->shmId);
}
}

?>
To Top