PHP檔案鎖
一、檔案鎖是什麼 ?
顧名思義,對檔案上鎖。
可以通過“進門”的實際情況來理解:
有多個人要通過一個大門到食堂裡吃飯,但食堂只有一個座位,食堂管理員A不希望讓人坐地上吃飯,所以就通知大家在門外排隊,一個人進來吃完後,下一個人才允許進來,所以當第一個人進大門後,管理員A把大門鎖上,等第一個人吃完後,再解鎖開啟大門讓第二個人進來,這就是阻塞型檔案鎖。
食堂管理員B卻有點偷懶,不想等那麼久,就告訴大家,中午都可以來食堂吃飯,但是要跑快點才行,只有一個座位,第一個到的人就可以在食堂吃飯,然後我就會鎖門,其他人看到門鎖上了就哪來的回哪去吧,這就是非阻塞新檔案鎖
二、檔案鎖有什麼作用 ?
鎖機制之所以存在是因為併發導致的資源競爭,為了確保操作的有效性和完整性,可以通過鎖機制將併發狀態轉換成序列狀態。作為鎖機制中的一種,PHP的檔案鎖也是為了應對資源競爭。
假設一個應用場景,在存在較大併發的情況下,通過fwrite向檔案尾部多次有序的寫入資料,不加鎖的情況下會發生什麼?多次有序的寫入操作相當於一個事務,我們此時需要保證這個事務的完整性,所以加鎖具有一定的必要性。
三、實際使用效果展示
1. 不使用檔案鎖
<?php $lock_file='temp.lock'; $fp=fopen($lock_file,'a+'); fwrite($fp, "打點:".date("Y-m-d H:i:s",time())."\n"); sleep(1); fclose($fp);
使用ab壓力測試器執行檔案十次,檢視temp.lock:
2. 使用非阻塞型檔案鎖
<?php $p_file = "temp.lock"; $fp = fopen($p_file, 'a+'); if ( !flock($fp, LOCK_EX + LOCK_NB) ) { exit; }else { flock($fp, LOCK_EX + LOCK_NB); fwrite($fp, "打點:".date("Y-m-d H:i:s",time())."\n"); sleep(1); flock($fp,LOCK_UN); fclose($fp); }
使用ab壓力測試器執行檔案十次,檢視temp.lock:
3. 使用阻塞型檔案鎖
<?php
$lock_file='temp.lock';
$fp=fopen($lock_file,'a+');
if( flock($fp,LOCK_EX) ){
fwrite($fp, "打點:".date("Y-m-d H:i:s",time())."\n");
sleep(1);
flock($fp,LOCK_UN);
fclose($fp);
}else{
unlink($lock_file);
}
使用ab壓力測試器執行檔案十次,檢視temp.lock:
四、總結
通過上面三個簡單程式碼示範,可以很清楚看到使用檔案鎖和不使用檔案鎖的區別,非阻塞型檔案鎖和阻塞型檔案鎖的區別。
在不使用檔案鎖時,十個併發訪問,同時執行插入操作,而且在這種情況下還會丟失3條請求連線。
在使用非阻塞型檔案鎖時,又會出現的問題是隻能有一條請求通過,其他的在併發的同時訪問到檔案已經加鎖,只好斷開請求。
阻塞型檔案鎖的結果很明顯地得到十條資料,並且按照1秒的順序插入,這也是我們想得到的效果。
所以,在併發量較小的一些場景,可以考慮使用阻塞型檔案鎖,但是如果只是要得到一條有效資料,其他的都可以忽略的話,那也可以使用非阻塞型檔案鎖。
檔案鎖的使用會增加伺服器 I/O 的消耗,因此還是儘量少用,訪問量較小、併發量小的情況下,可以考慮使用檔案鎖。
如果涉及資料庫操作順序的話,可以使用mysql鎖,但如果併發量太大的話,就要考慮使用快取鎖,利用快取的時間來進行加鎖控制。簡單提提,後面有時間再做專門的整理。
ps:不熟悉ab壓力測試工具的朋友參考我這篇文章:ab壓力測試工具