首页 >后端开发 >php教程 >PHP并发读写文件如何解决

PHP并发读写文件如何解决

小云云
小云云原创
2018-03-16 15:31:562589浏览

在并发高的情况下,操作同一个文件会导致数据错乱,所以需要在操作文件时进行一些特殊处理,下面总结一下几种解决方案。希望能帮助到大家。

方案一:使用flock函数对文件加锁

<span style="font-size: 14px;">/*  <br/>* flock(file,lock,block)  <br/>* file 必需,规定要锁定或释放的已打开的文件  <br/>* lock 必需。规定要使用哪种锁定类型。  <br/>* block 可选。若设置为 1 或 true,则当进行锁定时阻挡其他进程。  <br/>* lock  <br/>* LOCK_SH 要取得共享锁定(读取的程序)  <br/>* LOCK_EX 要取得独占锁定(写入的程序)  <br/>* LOCK_UN 要释放锁定(无论共享或独占)  <br/>* LOCK_NB 如果不希望 flock() 在锁定时堵塞  <br/>/*  <br/><br/>// 获取锁if (flock($file,LOCK_EX)) {    // 操作文件<br/>    fwrite($file,&#39;write more words&#39;);  <br/>    // 操作完毕后释放锁<br/>    flock($file,LOCK_UN);  <br/>} else {  <br/>    //处理错误逻辑  <br/>}  <br/>fclose($file);  <br/></span>

flock函数在多并发情况下,似乎会经常独占资源,不即时释放,或者是根本不释放,造成死锁,从而使服务器的cpu占用很高,甚至有时候会让服务器彻底死掉。所以单纯的使用flock加锁并不能完全解决问题。

方案二:限定加锁时间,超时则退出

<span style="font-size: 14px;">if($fp = fopen($fileName,&#39;a&#39;)) {    $startTime = microtime();    do{        $canWrite = flock($fp, LOCK_EX);        if(!$canWrite) {<br/>            usleep(round(rand(0, 100) * 1000));   // 释放cpu,将cpu资源先让给其他进程<br/>        }        // 如果未获取到锁,且未超时,则继续获取锁<br/>    } while((!$canWrite) && ((microtime() - $startTime) < 1000));    if($canWrite) {        fwrite($fp, $dataToSave);<br/>        flock($file,LOCK_UN);  <br/>    }    fclose($fp);<br/>}<br/></span>

方案三:使用临时文件

<span style="font-size: 14px;">$dir_fileopen=&#39;tmp&#39;;function cfopen($filename,$mode){<br/>    global $dir_fileopen;<br/>    clearstatcache();    // 创建一个临时文件<br/>    do{        $id=uniqid();        $tempfilename=$dir_fileopen.&#39;/&#39;.$id.md5($filename);<br/>    } while(file_exists($tempfilename));    // 将要操作的文件内容拷贝到临时文件中<br/>    copy($filename,$tempfilename);    $fp = fopen($tempfilename, $mode);    return $fp ? [$fp, $filename, $id, @filemtime($filename)] : false;<br/>}function cfwrite($fp,$string){<br/>    // 将新增内容写入到临时文件中<br/>    return fwrite($fp[0], $string);<br/>}function cfclose($fp){<br/>    global $dir_fileopen;    $success = fclose($fp[0]);<br/>    clearstatcache();    $tempfilename = $dir_fileopen.&#39;/&#39;.$fp[2].md5($fp[1]);    // 如果要操作的文件在操作期间没有被修改过,则说明没有人操作过该文件,那么将临时文件改名为真正的文件<br/>    if((@filemtime($fp[1]) == $fp[3])){<br/>        rename($tempfilename,$fp[1]);<br/>    }else{        //说明有其它进程在操作目标文件,当前进程被拒绝,删除临时文件<br/>        unlink($tempfilename);        $success = false;<br/>    }    return $success;<br/>}$startTime = microtime();do{    $fp=cfopen(&#39;lock.txt&#39;,&#39;a+&#39;);<br/>    cfwrite($fp,"welcome to beijing.\n");    $success = cfclose($fp, &#39;on&#39;);    if(!$success) {<br/>        usleep(round(rand(0, 100) * 1000));   // 释放cpu,将cpu资源先让给其他进程<br/>    }<br/>}while(!$success && ((microtime() - $startTime) < 1000));    // 如果为false,说明操作失败,则重新进行一次操作<br/></span>

方案四:使用队列

创建一个文件操作的队列,然后写一个脚本从队列中依次读取文件操作的信息再对文件进行相应的操作,这样每次就只有一个进程在操作文件,就解决了并发的问题。

以上内容参考自:http://blog.csdn.net/daiyan_csdn/article/details/51524781

在并发高的情况下,操作同一个文件会导致数据错乱,所以需要在操作文件时进行一些特殊处理,下面总结一下几种解决方案。

方案一:使用flock函数对文件加锁

<span style="font-size: 14px;">/*  <br/>* flock(file,lock,block)  <br/>* file 必需,规定要锁定或释放的已打开的文件  <br/>* lock 必需。规定要使用哪种锁定类型。  <br/>* block 可选。若设置为 1 或 true,则当进行锁定时阻挡其他进程。  <br/>* lock  <br/>* LOCK_SH 要取得共享锁定(读取的程序)  <br/>* LOCK_EX 要取得独占锁定(写入的程序)  <br/>* LOCK_UN 要释放锁定(无论共享或独占)  <br/>* LOCK_NB 如果不希望 flock() 在锁定时堵塞  <br/>/*  <br/><br/>// 获取锁if (flock($file,LOCK_EX)) {    // 操作文件<br/>    fwrite($file,&#39;write more words&#39;);  <br/>    // 操作完毕后释放锁<br/>    flock($file,LOCK_UN);  <br/>} else {  <br/>    //处理错误逻辑  <br/>}  <br/>fclose($file);  <br/></span>

flock函数在多并发情况下,似乎会经常独占资源,不即时释放,或者是根本不释放,造成死锁,从而使服务器的cpu占用很高,甚至有时候会让服务器彻底死掉。所以单纯的使用flock加锁并不能完全解决问题。

方案二:限定加锁时间,超时则退出

<span style="font-size: 14px;">if($fp = fopen($fileName,&#39;a&#39;)) {    $startTime = microtime();    do{        $canWrite = flock($fp, LOCK_EX);        if(!$canWrite) {<br/>            usleep(round(rand(0, 100) * 1000));   // 释放cpu,将cpu资源先让给其他进程<br/>        }        // 如果未获取到锁,且未超时,则继续获取锁<br/>    } while((!$canWrite) && ((microtime() - $startTime) < 1000));    if($canWrite) {        fwrite($fp, $dataToSave);<br/>        flock($file,LOCK_UN);  <br/>    }    fclose($fp);<br/>}<br/></span>

方案三:使用临时文件

<span style="font-size: 14px;">$dir_fileopen=&#39;tmp&#39;;function cfopen($filename,$mode){<br/>    global $dir_fileopen;<br/>    clearstatcache();    // 创建一个临时文件<br/>    do{        $id=uniqid();        $tempfilename=$dir_fileopen.&#39;/&#39;.$id.md5($filename);<br/>    } while(file_exists($tempfilename));    // 将要操作的文件内容拷贝到临时文件中<br/>    copy($filename,$tempfilename);    $fp = fopen($tempfilename, $mode);    return $fp ? [$fp, $filename, $id, @filemtime($filename)] : false;<br/>}function cfwrite($fp,$string){<br/>    // 将新增内容写入到临时文件中<br/>    return fwrite($fp[0], $string);<br/>}function cfclose($fp){<br/>    global $dir_fileopen;    $success = fclose($fp[0]);<br/>    clearstatcache();    $tempfilename = $dir_fileopen.&#39;/&#39;.$fp[2].md5($fp[1]);    // 如果要操作的文件在操作期间没有被修改过,则说明没有人操作过该文件,那么将临时文件改名为真正的文件<br/>    if((@filemtime($fp[1]) == $fp[3])){<br/>        rename($tempfilename,$fp[1]);<br/>    }else{        //说明有其它进程在操作目标文件,当前进程被拒绝,删除临时文件<br/>        unlink($tempfilename);        $success = false;<br/>    }    return $success;<br/>}$startTime = microtime();do{    $fp=cfopen(&#39;lock.txt&#39;,&#39;a+&#39;);<br/>    cfwrite($fp,"welcome to beijing.\n");    $success = cfclose($fp, &#39;on&#39;);    if(!$success) {<br/>        usleep(round(rand(0, 100) * 1000));   // 释放cpu,将cpu资源先让给其他进程<br/>    }<br/>}while(!$success && ((microtime() - $startTime) < 1000));    // 如果为false,说明操作失败,则重新进行一次操作<br/></span>

方案四:使用队列

创建一个文件操作的队列,然后写一个脚本从队列中依次读取文件操作的信息再对文件进行相应的操作,这样每次就只有一个进程在操作文件,就解决了并发的问题。

相关推荐:

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

以上是PHP并发读写文件如何解决的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn