亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2013年10月25日 09:27:21   作者:  
在這里提供4種高并發(fā)讀寫文件的方案,各有優(yōu)點(diǎn),可以根據(jù)自己的情況解決php并發(fā)讀寫文件沖突的問題。

對于日IP不高或者說并發(fā)數(shù)不是很大的應(yīng)用,一般不用考慮這些!用一般的文件操作方法完全沒有問題。但如果并發(fā)高,在我們對文件進(jìn)行讀寫操作時(shí),很有可能多個(gè)進(jìn)程對進(jìn)一文件進(jìn)行操作,如果這時(shí)不對文件的訪問進(jìn)行相應(yīng)的獨(dú)占,就容易造成數(shù)據(jù)丟失。
例如:一個(gè)在線聊天室(這里假定把聊天內(nèi)容寫入文件),在同一時(shí)刻,用戶A和用戶B都要操作數(shù)據(jù)保存文件,首先是A打開了文件,然后更新里面的數(shù)據(jù),但這里B也正好也打開了同一個(gè)文件,也準(zhǔn)備更新里面的數(shù)據(jù)。當(dāng)A把寫好的文件保存時(shí),這里其實(shí)B已經(jīng)打開了文件。但當(dāng)B再把文件保存回去時(shí),這里已經(jīng)造成了數(shù)據(jù)的丟失,因?yàn)檫@里B用戶完全不知道它所打開的文件在它對其進(jìn)行更改時(shí),A用戶也更改了這個(gè)文件,所以最后B用戶保存更改時(shí),用戶A的更新就被會(huì)丟失。
對于這樣的問題,一般的解決方案時(shí)當(dāng)一進(jìn)程對文件進(jìn)行操作時(shí),首先對其它進(jìn)行加鎖,意味著這里只有該進(jìn)程有權(quán)對文件進(jìn)行讀取,其它進(jìn)程如果現(xiàn)在讀,是完全沒有問題,但如果這時(shí)有進(jìn)程試圖想對其進(jìn)行更新,會(huì)遭到操作拒絕,先前對文件進(jìn)行加鎖的進(jìn)程這時(shí)如果對文件的更新操作完畢,這就釋放獨(dú)占的標(biāo)識,這時(shí)文件又恢復(fù)到了可更改的狀態(tài)。接下來同理,如果那個(gè)進(jìn)程在操作文件時(shí),文件沒有加鎖,這時(shí),它就可以放心大膽的對文件進(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之前,一定要慎重考慮。
那么就沒有解決方案了嗎?其實(shí)也不是這樣的。如果flock()我們使用得當(dāng),完全可能解決死鎖的問題。當(dāng)然如果不考慮使用flock()函數(shù),也同樣會(huì)有很好的解決方案來解決我們的問題。經(jīng)過我個(gè)人的搜集和總結(jié),大致歸納了解決方案有如下幾種。
方案一:對文件進(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)沒有獲得鎖,就反復(fù)獲得,直接獲得到對文件操作權(quán)為止,當(dāng)然。如果超時(shí)限制已到,就必需馬上退出,讓出鎖讓其它進(jìn)程來進(jìn)行操作。

方案二:不使用flock函數(shù),借用臨時(shí)文件來解決讀寫沖突的問題。大致原理如下:
(1)將需要更新的文件考慮一份到我們的臨時(shí)文件目錄,將文件最后修改時(shí)間保存到一個(gè)變量,并為這個(gè)臨時(shí)文件取一個(gè)隨機(jī)的,不容易重復(fù)的文件名。
(2)當(dāng)對這個(gè)臨時(shí)文件進(jìn)行更新后,再檢測原文件的最后更新時(shí)間和先前所保存的時(shí)間是否一致。
(3)如果最后一次修改時(shí)間一致,就將所修改的臨時(shí)文件重命名到原文件,為了確保文件狀態(tài)同步更新,所以需要清除一下文件狀態(tài)。
(4)但是,如果最后一次修改時(shí)間和先前所保存的一致,這說明在這期間,原文件已經(jīng)被修改過,這時(shí),需要把臨時(shí)文件刪除,然后返回false,說明文件這時(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);
  //說明有其它進(jìn)程 在操作目標(biāo)文件,當(dāng)前進(jìn)程被拒絕
        $success=false;
    }
    return $success;
}
$fp=cfopen('lock.txt','a+');
cfwrite($fp,"welcome to beijing.\n");
fclose($fp,'on');

對于上面的代碼所使用的函數(shù),需要說明一下:
(1)rename();重命名一個(gè)文件或一個(gè)目錄,該函數(shù)其實(shí)更像linux里的mv。更新文件或者目錄的路徑或名字很方便。但當(dāng)我在window測試上面代碼時(shí),如果新文件名已經(jīng)存在,會(huì)給出一個(gè)notice,說當(dāng)前文件已經(jīng)存在。但在linux下工作的很好。
(2)clearstatcache();清除文件的狀態(tài).php將緩存所有文件屬性信息,以提供更高的性能,但有時(shí),多進(jìn)程在對文件進(jìn)行刪除或者更新操作時(shí),php沒來得及更新緩存里的文件屬性,容易導(dǎo)致訪問到最后更新時(shí)間不是真實(shí)的數(shù)據(jù)。所以這里需要使用該函數(shù)對已保存的緩存進(jìn)行清除。

方案三:對操作的文件進(jìn)行隨機(jī)讀寫,以降低并發(fā)的可能性。
在對用戶訪問日志進(jìn)行記錄時(shí),這種方案似乎被采用的比較多。先前需要定義一個(gè)隨機(jī)空間,空間越大,并發(fā)的的可能性就越小,這里假設(shè)隨機(jī)讀寫空間為[1-500],那么我們的日志文件的分布就為log1~到log500不等。每一次用戶訪問,都將數(shù)據(jù)隨機(jī)寫到log1~log500之間的任一文件。在同一時(shí)刻,有2個(gè)進(jìn)程進(jìn)行記錄日志,A進(jìn)程可能是更新的log32文件,而B進(jìn)程呢?則此時(shí)更新的可能就為log399.要知道,如果要讓B進(jìn)程也操作log32,概率基本上為1/500,差不多約等于零。在需要對訪問日志進(jìn)行分析時(shí),這里我們只需要先將這些日志合并,再進(jìn)行分析即可。使用這種方案來記錄日志的一個(gè)好處時(shí),進(jìn)程操作排隊(duì)的可能性比較小,可以使進(jìn)程很迅速的完成每一次操作。

方案四:將所有要操作的進(jìn)程放入一個(gè)隊(duì)列中。然后專門放一個(gè)服務(wù)完成文件操作。隊(duì)列中的每一個(gè)排除的進(jìn)程相當(dāng)于第一個(gè)具體的操作,所以第一次我們的服務(wù)只需要從隊(duì)列中取得相當(dāng)于具體操作事項(xiàng)就可以了,如果這里還有大量的文件操作進(jìn)程,沒關(guān)系,排到我們的隊(duì)列后面即可,只要愿意排,隊(duì)列的多長都沒關(guān)系。

對于以前幾種方案,各有各的好處!大致可能歸納為兩類:
(1)需要排隊(duì)(影響慢)比如方案一、二、四
(2)不需要排隊(duì)。(影響快)方案三
在設(shè)計(jì)緩存系統(tǒng)時(shí),一般我們不會(huì)采用方案三。因?yàn)榉桨溉姆治龀绦蚝蛯懭氤绦蚴遣煌降?,在寫的時(shí)間,完全不考慮到時(shí)候分析的難度,只管寫的行了。試想一下,如我們在更新一個(gè)緩存時(shí),如果也采用隨機(jī)文件讀寫法,那么在讀緩存時(shí)似乎會(huì)增加很多流程。但采取方案一、二就完全不一樣,雖然寫的時(shí)間需要等待(當(dāng)獲取鎖不成功時(shí),會(huì)反復(fù)獲?。?,但讀文件是很方便的。添加緩存的目的就是要減少數(shù)據(jù)讀取瓶頸,從而提高系統(tǒng)性能。
從上為個(gè)人經(jīng)驗(yàn)和一些資料的總結(jié),有什么不對的地方,或者沒有談到的地方,歡迎各位同行指正。

相關(guān)文章

  • PHP.vs.JAVA

    PHP.vs.JAVA

    php在諸多方面都不如java優(yōu)異,那么php開發(fā)出的oa產(chǎn)品何以與java產(chǎn)品競爭呢?在于Php陣營普遍走的是低端路線,而java陣營走的是中高端路線。兩者之間交叉的區(qū)域較小。
    2016-04-04
  • 怎樣去閱讀一份php源代碼

    怎樣去閱讀一份php源代碼

    技術(shù)的快速進(jìn)步,最好的途徑就是閱讀源代碼了。自己也閱讀了很多開源的程序,感覺方法很重要,好的方法可以達(dá)到事半功倍的效果。一下就是我自己的一些新的,希望對大家都有用。
    2009-08-08
  • PHP 加密與解密的斗爭

    PHP 加密與解密的斗爭

    PHP代碼的保護(hù)一直是許多公司關(guān)注的核心問題,例如知名的一些論壇vBulletin、Discuz!、PhpWind及近日很火的ShopEx等等
    2009-04-04
  • PHP 開源框架22個(gè)簡單簡介

    PHP 開源框架22個(gè)簡單簡介

    PHP 是一個(gè)被廣泛使用的來進(jìn)行Web開發(fā)的腳本語言。雖然有很多其它可供選擇的Web開發(fā)語言,像:ASP 和Ruby,但是PHP是目前為止世界上最為流行的。
    2009-08-08
  • javascript 小型動(dòng)畫組件與實(shí)現(xiàn)代碼

    javascript 小型動(dòng)畫組件與實(shí)現(xiàn)代碼

    javascript 小型動(dòng)畫組件與實(shí)現(xiàn)代碼,想要學(xué)習(xí)js動(dòng)畫的朋友可以參考下。思路確實(shí)很實(shí)用。
    2010-06-06
  • 測試您的 PHP 水平的題目

    測試您的 PHP 水平的題目

    測試您的 PHP 水平的題目...
    2007-05-05
  • PHP程序員面試 切忌急功近利(更需要注重以后的發(fā)展)

    PHP程序員面試 切忌急功近利(更需要注重以后的發(fā)展)

    招聘一個(gè)程序員,唯一對你有意義的是他能寫出好程序的能力。 很少人像這樣去招人,他們更喜歡去挑剔程序員的個(gè)人癖好和性格缺點(diǎn)。
    2010-09-09
  • dedecms 制作模板中使用的全局標(biāo)記圖文教程

    dedecms 制作模板中使用的全局標(biāo)記圖文教程

    dedecms 制作模板中使用的全局標(biāo)記圖文教程...
    2007-03-03
  • php格式化工具Beautify PHP小小BUG

    php格式化工具Beautify PHP小小BUG

    Beautify PHP is written entirely in PHP. The program was tested with Linux and Windows, PHP 4.1.0 and PHP 4.3.1, but it should work on most systems running PHP.
    2008-04-04
  • 成為好程序員必須避免的5個(gè)壞習(xí)慣

    成為好程序員必須避免的5個(gè)壞習(xí)慣

    這篇文章主要介紹了成為好程序員的必須避免的5個(gè)壞習(xí)慣,寫的很好啊,小編總結(jié),不管做什么都要總結(jié)出自己的一套東西,需要的朋友可以參考下
    2014-07-07

最新評論