PHP檔案函數flock
? ? ? ? 並發情況下,PHP該如何寫檔案?其實這個問題不只是PHP面臨的問題。不管是線程還是進程,當並發寫的時候,都會遇到共用資源寫衝突。軟體開發過程中,寫衝突無處不在,比如多線程寫共用變數,比如資料庫多串連並發寫資料,比如多進程寫檔案等等。那麼這些都該如何處理呢?目前普遍的處理辦法就是給共用資源上獨佔鎖(寫鎖)。
? ? ? ? PHP在第三版的時候就提供了一個函數flock,顧名思義,檔案鎖操作函數。檔案鎖機制是依賴於宿主檔案系統的,也就是說,如何個鎖法,是宿主檔案系統說了算,flock只是個外殼函數,裡面調用了檔案系統的鎖機制。
? ? ? ? 鎖的話,分為兩種類型,讀鎖和寫鎖。寫鎖也叫排它鎖、獨佔鎖,就是一個線程或進程獨佔資源,別的線程或進程無法使用資源,保證寫資料不受幹擾,不衝突;讀鎖也叫共用鎖定,允許多個線程或進程同時讀,但不能有寫的操作。
函數原型:
?
flock ($handle, $operation, &$wouldblock = null);
?
參數說明:
$handle //檔案指標
$operation //鎖類型
$operation 有幾個可用值:LOCK_EX【寫鎖】、LOCK_SH【讀鎖】、LOCK_UN【釋放鎖】
? ? ? ? 看個例子吧
?
function fileWrite($file){$fp = fopen($file, 'a');flock($fp, LOCK_EX);//上寫鎖/*寫資料*/fwrite($fp, "1");fwrite($fp, "2");fwrite($fp, "3\r\n");flock($fp, LOCK_UN);//釋放鎖fclose($fp);}fileWrite('D:/txt.txt');? ? ? ? 用Jmeter做下並發測試,執行3000次請求,會發現檔案裡有3000行123(不考慮apache或nginx的效能瓶頸)。
?
? ? ? ? 在用Jmeter做並發測試的時候,用記事本開啟這個檔案,改點東西,然後點擊儲存,你會發現情況
? ? ? ? 這就是因為檔案上鎖了,記事本進程無法寫入。
? ? ? ? 前邊說了,flock函數的鎖機制實際上是檔案系統的鎖機制,它封裝了某些類型檔案系統的鎖機制,有些檔案系統flock不支援,據PHP手冊上說,FAT、NTF等這種老式檔案系統和網路檔案系統,flock不支援。本人沒測過。
? ? ? ? PHP手冊還說,flock是進程層級的,多線程的時候不起作用。可能大家就要有疑惑了,PHP又沒線程的概念。那把PHP放在支援多線程的伺服器上呢,大家想想看。測一測。
分析到這一步呢,會發現flock依賴宿主,對環境有要求,這就深深的傷害了代碼的可移植性。怕啦!!別怕,其實傷害也沒多深,flock還是能滿足大部分環境的。
?
? ? ? ? 針對flock的移植性稍有些不足,大家就開始研究替代辦法,我也關注了下,發現網上流傳著下面這樣的代碼
?
function fileWrite($file,$content){$lock = $file.'.lock';while (true) {if (file_exists($lock)) {usleep(100);}else{touch($lock);//上鎖file_put_contents($file, $content, FILE_APPEND);//寫檔案@unlink($lock);//刪除鎖break;}}}fileWrite('D:/txt.txt','i m a phper');
? ? ? ? 你覺著這段代碼有鎖作用嗎??測測!!其實都不用測,一看就鎖不住,file_exists本來就可以並存執行,當兩進程同時執行到file_exists,判斷所謂的鎖檔案不存在,結果還不是衝突著呢。
鎖,實際上是將並發訪問排隊阻塞序列化,然後依次處理訪問,上邊這段代碼連排隊都沒有,怎麼能上鎖呢。
? ? 這時候大家可能又會問多個進程同時執行flock,不也是並行的嗎?是,執行flock是並行的,這隻是代表申請鎖是並行的,flock內部調的是宿主檔案系統,自然會把鎖請求排隊處理。
?