一般的方案會是:
復制代碼 代碼如下:
$fp = fopen("/tmp/lock.txt", "w+");
if (flock($fp, LOCK_EX)) {
fwrite($fp, "Write something heren");
flock($fp, LOCK_UN);
} else {
echo "Couldn't lock the file !";
}
fclose($fp);
復制代碼 代碼如下:
if($fp = fopen($fileName, 'a')) {
$startTime = microtime();
do {
$canWrite = flock($fp, LOCK_EX);
if(!$canWrite) usleep(round(rand(0, 100)*1000));
} while ((!$canWrite)&& ((microtime()-$startTime) < 1000));
if ($canWrite) {
fwrite($fp, $dataToSave);
}
fclose($fp);
}
復制代碼 代碼如下:
$dir_fileopen = "tmp";
function randomid() {
return time().substr(md5(microtime()), 0, rand(5, 12));
}
function cfopen($filename, $mode) {
global $dir_fileopen;
clearstatcache();
do {
$id = md5(randomid(rand(), TRUE));
$tempfilename = $dir_fileopen."/".$id.md5($filename);
} while(file_exists($tempfilename));
if (file_exists($filename)) {
$newfile = false;
copy($filename, $tempfilename);
}else{
$newfile = true;
}
$fp = fopen($tempfilename, $mode);
return $fp ? array($fp, $filename, $id, @filemtime($filename)) : false;
}
function cfwrite($fp,$string) { return fwrite($fp[0], $string); }
function cfclose($fp, $debug = "off") {
global $dir_fileopen;
$success = fclose($fp[0]);
clearstatcache();
$tempfilename = $dir_fileopen."/".$fp[2].md5($fp[1]);
if ((@filemtime($fp[1]) == $fp[3]) || ($fp[4]==true && !file_exists($fp[1])) || $fp[5]==true) {
rename($tempfilename, $fp[1]);
}else{
unlink($tempfilename);
//說明有其它進程 在操作目標文件,當前進程被拒絕
$success = false;
}
return $success;
}
$fp = cfopen('lock.txt','a+');
cfwrite($fp,"welcome to beijing.n");
fclose($fp,'on');
對于上面的代碼所使用的函數,需要說明一下:
1.rename();重命名一個文件或一個目錄,該函數其實更像linux里的mv。更新文件或者目錄的路徑或名字很方便。
但當我在window測試上面代碼時,如果新文件名已經存在,會給出一個notice,說當前文件已經存在。但在linux下工作的很好。
2.clearstatcache();清除文件的狀態.php將緩存所有文件屬性信息,以提供更高的性能,但有時,多進程在對文件進行刪除或者更新操作時,php沒來得及更新緩存里的文件屬性,容易導致訪問到最后更新時間不是真實的數據。所以這里需要使用該函數對已保存的緩存進行清除。
方案三:對操作的文件進行隨機讀寫,以降低并發的可能性。
在對用戶訪問日志進行記錄時,這種方案似乎被采用的比較多。
先前需要定義一個隨機空間,空間越大,并發的的可能性就越小,這里假設隨機讀寫空間為[1-500],那么我們的日志文件的分布就為log1~到log500不等。每一次用戶訪問,都將數據隨機寫到log1~log500之間的任一文件。
在同一時刻,有2個進程進行記錄日志,A進程可能是更新的log32文件,而B進程呢?則此時更新的可能就為log399.要知道,如果要讓B進程也操作log32,概率基本上為1/500,差不多約等于零。
在需要對訪問日志進行分析時,這里我們只需要先將這些日志合并,再進行分析即可。
使用這種方案來記錄日志的一個好處時,進程操作排隊的可能性比較小,可以使進程很迅速的完成每一次操作。
方案四:將所有要操作的進程放入一個隊列中。然后專門放一個服務完成文件操作。
隊列中的每一個排除的進程相當于第一個具體的操作,所以第一次我們的服務只需要從隊列中取得相當于具體操作事項就可以了,如果這里還有大量的文件操作進程,沒關系,排到我們的隊列后面即可,只要愿意排,隊列的多長都沒關系。
對于以前幾種方案,各有各的好處!大致可能歸納為兩類:
1、需要排隊(影響慢)比如方案一、二、四
2、不需要排隊。(影響快)方案三
在設計緩存系統時,一般我們不會采用方案三。因為方案三的分析程序和寫入程序是不同步的,在寫的時間,完全不考慮到時候分析的難度,只管寫的行了。試想一下,如我們在更新一個緩存時,如果也采用隨機文件讀寫法,那么在讀緩存時似乎會增加很多流程。但采取方案一、二就完全不一樣,雖然寫的時間需要等待(當獲取鎖不成功時,會反復獲?。x文件是很方便的。添加緩存的目的就是要減少數據讀取瓶頸,從而提高系統性能。
新聞熱點
疑難解答