PHP并发读写文件的解决方案

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

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

/*  
* flock(file,lock,block)  
* file 必需,规定要锁定或释放的已打开的文件  
* lock 必需。规定要使用哪种锁定类型。  
* block 可选。若设置为 1true,则当进行锁定时阻挡其他进程。  
* 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);  

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

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

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

方案三:使用临时文件

$dir_fileopen='tmp';

function cfopen($filename,$mode){
    global $dir_fileopen;
    clearstatcache();
    // 创建一个临时文件
    do{
        $id=uniqid();
        $tempfilename=$dir_fileopen.'/'.$id.md5($filename);
    } while(file_exists($tempfilename));
    // 将要操作的文件内容拷贝到临时文件中
    copy($filename,$tempfilename);
    $fp = fopen($tempfilename, $mode);
    return $fp ? [$fp, $filename, $id, @filemtime($filename)] : false;
}

function cfwrite($fp,$string){
    // 将新增内容写入到临时文件中
    return fwrite($fp[0], $string);
}

function cfclose($fp){
    global $dir_fileopen;
    $success = fclose($fp[0]);
    clearstatcache();
    $tempfilename = $dir_fileopen.'/'.$fp[2].md5($fp[1]);

    // 如果要操作的文件在操作期间没有被修改过,则说明没有人操作过该文件,那么将临时文件改名为真正的文件
    if((@filemtime($fp[1]) == $fp[3])){
        rename($tempfilename,$fp[1]);
    }else{
        //说明有其它进程在操作目标文件,当前进程被拒绝,删除临时文件
        unlink($tempfilename);
        $success = false;
    }
    return $success;
}

$startTime = microtime();
do{
    $fp=cfopen('lock.txt','a+');
    cfwrite($fp,"welcome to beijing.\n");
    $success = cfclose($fp, 'on');
    if(!$success) {
        usleep(round(rand(0, 100) * 1000));   // 释放cpu,将cpu资源先让给其他进程
    }
}while(!$success && ((microtime() - $startTime) < 1000));    // 如果为false,说明操作失败,则重新进行一次操作

方案四:使用队列

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

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值