国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > PHP > 正文

php中并發(fā)讀寫(xiě)文件沖突的解決方案

2020-03-22 19:15:42
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
對(duì)于日IP不高或者說(shuō)并發(fā)數(shù)不是很大的應(yīng)用,一般不用考慮這些!用一般的文件操作方法完全沒(méi)有問(wèn)題。但如果并發(fā)高,在我們對(duì)文件進(jìn)行讀寫(xiě)操作時(shí),很有可能多個(gè)進(jìn)程對(duì)進(jìn)一文件進(jìn)行操作,如果這時(shí)不對(duì)文件的訪問(wèn)進(jìn)行相應(yīng)的獨(dú)占,就容易造成數(shù)據(jù)丟失。
例如:一個(gè)在線聊天室(這里假定把聊天內(nèi)容寫(xiě)入文件),在同一時(shí)刻,用戶(hù)A和用戶(hù)B都要操作數(shù)據(jù)保存文件,首先是A打開(kāi)了文件,然后更新里面的數(shù)據(jù),但這里B也正好也打開(kāi)了同一個(gè)文件,也準(zhǔn)備更新里面的數(shù)據(jù)。當(dāng)A把寫(xiě)好的文件保存時(shí),這里其實(shí)B已經(jīng)打開(kāi)了文件。但當(dāng)B再把文件保存回去時(shí),這里已經(jīng)造成了數(shù)據(jù)的丟失,因?yàn)檫@里B用戶(hù)完全不知道它所打開(kāi)的文件在它對(duì)其進(jìn)行更改時(shí),A用戶(hù)也更改了這個(gè)文件,所以最后B用戶(hù)保存更改時(shí),用戶(hù)A的更新就被會(huì)丟失。
對(duì)于這樣的問(wèn)題,一般的解決方案時(shí)當(dāng)一進(jìn)程對(duì)文件進(jìn)行操作時(shí),首先對(duì)其它進(jìn)行加鎖,意味著這里只有該進(jìn)程有權(quán)對(duì)文件進(jìn)行讀取,其它進(jìn)程如果現(xiàn)在讀,是完全沒(méi)有問(wèn)題,但如果這時(shí)有進(jìn)程試圖想對(duì)其進(jìn)行更新,會(huì)遭到操作拒絕,先前對(duì)文件進(jìn)行加鎖的進(jìn)程這時(shí)如果對(duì)文件的更新操作完畢,這就釋放獨(dú)占的標(biāo)識(shí),這時(shí)文件又恢復(fù)到了可更改的狀態(tài)。接下來(lái)同理,如果那個(gè)進(jìn)程在操作文件時(shí),文件沒(méi)有加鎖,這時(shí),它就可以放心大膽的對(duì)文件進(jìn)行鎖定,獨(dú)自享用。
一般的方案會(huì)是:
復(fù)制代碼 代碼如下:
$fp=fopen('/tmp/lock.txt','w+');
if (flock($fp,LOCK_EX)){
fwrite($fp,"Write something here/n");
flock($fp,LOCK_UN);
}else{
echo 'Couldn/'t lock the file !';
}
fclose($fp);

但在PHP中,flock似乎工作的不是那么好!在多并發(fā)情況下,似乎是經(jīng)常獨(dú)占資源,不即時(shí)釋放,或者是根本不釋放,造成死鎖,從而使服務(wù)器的cpu占用很高,甚至有時(shí)候會(huì)讓服務(wù)器徹底死掉。好像在很多l(xiāng)inux/unix系統(tǒng)中,都會(huì)有這樣的情況發(fā)生。所以使用flock之前,一定要慎重考慮。
那么就沒(méi)有解決方案了嗎?其實(shí)也不是這樣的。如果flock()我們使用得當(dāng),完全可能解決死鎖的問(wèn)題。當(dāng)然如果不考慮使用flock()函數(shù),也同樣會(huì)有很好的解決方案來(lái)解決我們的問(wèn)題。經(jīng)過(guò)我個(gè)人的搜集和總結(jié),大致歸納了解決方案有如下幾種。
方案一:對(duì)文件進(jìn)行加鎖時(shí),設(shè)置一個(gè)超時(shí)時(shí)間。大致實(shí)現(xiàn)如下:
復(fù)制代碼 代碼如下:
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);
}

超時(shí)設(shè)置為1ms,如果這里時(shí)間內(nèi)沒(méi)有獲得鎖,就反復(fù)獲得,直接獲得到對(duì)文件操作權(quán)為止,當(dāng)然。如果超時(shí)限制已到,就必需馬上退出,讓出鎖讓其它進(jìn)程來(lái)進(jìn)行操作。方案二:不使用flock函數(shù),借用臨時(shí)文件來(lái)解決讀寫(xiě)沖突的問(wèn)題。大致原理如下:
(1)將需要更新的文件考慮一份到我們的臨時(shí)文件目錄,將文件最后修改時(shí)間保存到一個(gè)變量,并為這個(gè)臨時(shí)文件取一個(gè)隨機(jī)的,不容易重復(fù)的文件名。
(2)當(dāng)對(duì)這個(gè)臨時(shí)文件進(jìn)行更新后,再檢測(cè)原文件的最后更新時(shí)間和先前所保存的時(shí)間是否一致。
(3)如果最后一次修改時(shí)間一致,就將所修改的臨時(shí)文件重命名到原文件,為了確保文件狀態(tài)同步更新,所以需要清除一下文件狀態(tài)。
(4)但是,如果最后一次修改時(shí)間和先前所保存的一致,這說(shuō)明在這期間,原文件已經(jīng)被修改過(guò),這時(shí),需要把臨時(shí)文件刪除,然后返回false,說(shuō)明文件這時(shí)有其它進(jìn)程在進(jìn)行操作。
實(shí)現(xiàn)代碼如下:
復(fù)制代碼 代碼如下:
$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);
//說(shuō)明有其它進(jìn)程 在操作目標(biāo)文件,當(dāng)前進(jìn)程被拒絕

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 隆尧县| 长宁县| 雅江县| 夏河县| 盐山县| 高陵县| 来宾市| 西乌珠穆沁旗| 论坛| 石景山区| 基隆市| 南丰县| 贞丰县| 依兰县| 台前县| 漳浦县| 县级市| 锦州市| 兴国县| 枞阳县| 汕尾市| 腾冲县| 无棣县| 和静县| 红安县| 岑溪市| 德清县| 共和县| 奈曼旗| 万源市| 饶河县| 缙云县| 云浮市| 东莞市| 鹤山市| 溧阳市| 子洲县| 甘谷县| 大理市| 富顺县| 莫力|