看來 add() 函式確實是 100% 原子性的,而另一個評論中提到的 safeadd 自行車是沒用的。有一些連結,Memcahed 的開發人員在其中更深入地解釋了它
http://lists.danga.com/pipermail/memcached/2008-March/006647.html
http://www.serverphorums.com/read.php?9,214222
(PECL memcache >= 0.2.0)
Memcache::add — 在伺服器上新增一個項目
Memcache::add() 僅在伺服器上尚不存在此鍵時,才會使用 key
儲存變數 var
。您也可以使用 memcache_add() 函式。
key
將與該項目關聯的鍵。
var
要儲存的變數。字串和整數會按原樣儲存,其他型別會以序列化的方式儲存。
flag
使用 MEMCACHE_COMPRESSED
來以壓縮方式儲存項目 (使用 zlib)。
expire
項目的到期時間。如果等於零,則項目永遠不會過期。您也可以使用 Unix 時間戳記或從目前時間開始的秒數,但後者的秒數不得超過 2592000 (30 天)。
成功時回傳 true
,失敗時回傳 false
。如果此鍵已存在,則回傳 false
。對於其餘部分,Memcache::add() 的行為與 Memcache::set() 類似。
範例 1 Memcache::add() 範例
<?php
$memcache_obj = memcache_connect("localhost", 11211);
/* 程序式 API */
memcache_add($memcache_obj, 'var_key', '測試變數', false, 30);
/* 物件導向 API */
$memcache_obj->add('var_key', '測試變數', false, 30);
?>
看來 add() 函式確實是 100% 原子性的,而另一個評論中提到的 safeadd 自行車是沒用的。有一些連結,Memcahed 的開發人員在其中更深入地解釋了它
http://lists.danga.com/pipermail/memcached/2008-March/006647.html
http://www.serverphorums.com/read.php?9,214222
當多個執行緒嘗試執行 memcache_add 時,在高負載伺服器上會發生競爭條件。
例如,如果執行緒 A 和執行緒 B 嘗試儲存相同的鍵,您可以測試有時兩者都會回傳 TRUE。
為了獲得正確的行為,您可以驗證正確的值是否在指定的鍵中
<?php
function memcache_safeadd(&$memcache_obj, $key, $value, $flag, $expire)
{
if (memcache_add($memcache_obj, $key, $value, $flag, $expire))
{
return ($value == memcache_get($memcache_obj, $key));
}
return FALSE;
}
?>
用於遞增計數器的執行緒安全更新程式骨架
<?php
$key = "counter";
$value = $memcache->increment($key, 1);
if ($value === false) {
// --- 從資料庫讀取 ---
$query = "SELECT value FROM database";
$result = mysql_query($query);
$row = mysql_fetch_assoc($result);
$db_value = $row["value"];
$add_value = $memcache->add($key, $db_value + 1, 0, 0);
if ($add_value === false) {
$value = $memcache->increment($key, 1)
if ($value === false) {
error_log ("計數器更新失敗。");
}
} else {
$value = $db_value + 1;
}
}
// --- 顯示計數器值 ---
echo $value;
?>
[c.2007]
如果你閱讀 MMC_SERIALIZED 的原始碼,你會在第 ~1555 行看到 [大約在第 1560 行]
!(is_string,is_long,is_double,is_bool)
[是]序列化的,並且這些序列化值會被標記為 MMC_SERIALIZED 以便回傳(提取)程式碼再次反序列化這些值。