站长资讯网
最全最丰富的资讯网站

php怎么解决多进程同时写一个文件的问题?

php解决多进程同时写一个文件的方法:首先复制需要更新的文件,并更改文件名;然后检查最后更新时间和先前所保存的时间是否一致;最后将所修改的临时文件重命名到原文件。

php怎么解决多进程同时写一个文件的问题?


php解决多进程同时写一个文件的方法:

首先PHP是支持进程的而不支持多线程(这个先搞清楚了),如果是对于文件操作,其实你只需要给文件加锁就能解决,不需要其它操作,PHP的flock已经帮你搞定了。
用flock在写文件前先锁上,等写完后解锁,这样就实现了多线程同时读写一个文件避免冲突。大概就是下面这个流程

/* *flock(file,lock,block) *file 必需,规定要锁定或释放的已打开的文件 *lock 必需。规定要使用哪种锁定类型。 *block 可选。若设置为 1 或 true,则当进行锁定时阻挡其他进程。 *lock *LOCK_SH 要取得共享锁定(读取的程序) *LOCK_EX 要取得独占锁定(写入的程序) *LOCK_UN 要释放锁定(无论共享或独占) *LOCK_NB 如果不希望 flock() 在锁定时堵塞 /* if (flock($file,LOCK_EX)) { fwrite($file,'write more words'); flock($file,LOCK_UN); } else { //处理错误逻辑 } fclose($file); )

相关学习推荐:PHP编程从入门到精通

方案:不使用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);     }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);   //说明有其它进程 在操作目标文件,当前进程被拒绝         $success=false;     }     return $success; } $fp=cfopen('lock.txt','a+'); cfwrite($fp,"welcome to beijing.n"); fclose($fp,'on');

对于上面的代码所使用的函数,需要说明一下:

(1)rename();重命名一个文件或一个目录,该函数其实更像linux里的mv。更新文件或者目录的路径或名字很方便。但当我在window测试上面代码时,如果新文件名已经存在,会给出一个notice,说当前文件已经存在。但在linux下工作的很好。

(2)clearstatcache();清除文件的状态.php将缓存所有文件属性信息,以提供更高的性能,但有时,多进程在对文件进行删除或者更新操作时,php没来得及更新缓存里的文件属性,容易导致访问到最后更新时间不是真实的数据。所以这里需要使用该函数对已保存的缓存进行清除。

赞(0)
分享到: 更多 (0)