WE’RE
HERE

We’ll be happy to hear fram you, don’t
hesitate to get in touch

如何解决php中并发读写文件冲突的问题

浏览次数:100发布时间:2015/12/28文章来源:华仕尊城设计文章分类:APP与移动网站
如何解决php中并发读写文件冲突的问题 对于日IP不高或者说并发数不是很大的应用,一般不用考虑这些!用一般的文件操作方法完全没有问题。但如果并...2015/12/28

如何解决php中并发读写文件冲突的问题

对于日IP不高或者说并发数不是很大的应用,一般不用考虑这些!用一般的文件操作方法完全没有问题。但如果并发高,在我们对文件进行读写操作时,很有可能多个进程对进一文件进行操作,如果这时不对文件的访问进行相应的独占,就容易造成数据丢失。

例如:一个在线聊天室(这里假定把聊天内容写入文件),在同一时刻,用户A和用户B都要操作数据保存文件,首先是A打开了文件,然后更新里面的 数据,但这里B也正好也打开了同一个文件,也准备更新里面的数据。当A把写好的文件保存时,这里其实B已经打开了文件。但当B再把文件保存回去时,这里已 经造成了数据的丢失,因为这里B用户完全不知道它所打开的文件在它对其进行更改时,A用户也更改了这个文件,所以最后B用户保存更改时,用户A的更新就被 会丢失。

对于这样的问题,一般的解决方案时当一进程对文件进行操作时,首先对其它进行加锁,意味着这里只有该进程有权对文件进行读取,其它进程如果现在 读,是完全没有问题,但如果这时有进程试图想对其进行更新,会遭到操作拒绝,先前对文件进行加锁的进程这时如果对文件的更新操作完毕,这就释放独占的标 识,这时文件又恢复到了可更改的状态。接下来同理,如果那个进程在操作文件时,文件没有加锁,这时,它就可以放心大胆的对文件进行锁定,独自享用。

所以一般的方案会是:

$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);

但在PHP中,flock似乎工作的不是那么好!在多并发情况下,似乎是经常独占资源,不即时释放,或者是根本不释放,造成死锁,从而使服务器 的cpu占用很高,甚至有时候会让服务器彻底死掉。好像在很多linux/unix系统中,都会有这样的情况发生。所以使用flock之前,一定要慎重考 虑。

那么就没有解决方案了吗?其实也不是这样的。如果flock()我们使用得当,完全可能解决死锁的问题。当然如果不考虑使用flock()函数,也同样会有很好的解决方案来解决我们的问题。经过我个人的搜集和总结,大致归纳了解决方案有如下几种。

方案一:对文件进行加锁时,设置一个超时时间。大致实现如下:

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);

}

超时设置为1ms,如果这里时间内没有获得锁,就反复获得,直接获得到对文件操作权为止,当然。如果超时限制已到,就必需马上退出,让出锁让其它进程来进行操作。

方案二:不使用flock函数,借用临时文件来解决读写冲突的问题。大致原理如下:

(1)将需要更新的文件考虑一份到我们的临时文件目录,将文件最后修改时间保存到一个变量,并为这个临时文件取一个随机的,不容易重复的文件名。

(2)当对这个临时文件进行更新后,再检测原文件的最后更新时间和先前所保存的时间是否一致。

(3)如果最后一次修改时间一致,就将所修改的临时文件重命名到原文件,为了确保文件状态同步更新,所以需要清除一下文件状态。

(4)但是,如果最后一次修改时间和先前所保存的一致,这说明在这期间,原文件已经被修改过,这时,需要把临时文件删除,然后返回false,说明文件这时有其它进程在进行操作。

大致实现代码如下:

$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);

咨询电话:0755/29555722

(+86) 0755 2955 8889

518000

深圳宝安.西乡宝源.F518时尚创意园.17栋2楼

体验手机版您可以免费体验我们的服务(即时回复)

WWW.W-VI.COM
Copyright © W-Design. All Rights Reserved. 华仕尊城 版权所有 粤ICP 12007005-1 手机版 盗版必究 法律声明