ホームページ > バックエンド開発 > PHPチュートリアル > PHP でのファイルの同時読み取りと書き込みの問題を解決する方法

PHP でのファイルの同時読み取りと書き込みの問題を解決する方法

小云云
リリース: 2023-03-21 16:10:01
オリジナル
2600 人が閲覧しました

高い同時実行性の場合、同じファイルを操作するとデータの混乱が生じるため、ファイルを操作するときにいくつかの特別な処理が必要になります。ここではいくつかの解決策を示します。皆さんのお役に立てれば幸いです。

オプション 1: 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 を使用してロックするだけでは問題を完全に解決することはできません。

オプション 2: ロック時間を制限し、タイムアウトになったら終了

<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>
ログイン後にコピー
ログイン後にコピー

オプション 3: 一時ファイルを使用する

<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>
ログイン後にコピー
ログイン後にコピー

オプション 4: キューを使用する

ファイル操作用のキューを作成して書き込みますa スクリプトはファイル操作情報をキューから順番に読み取り、ファイルに対して対応する操作を実行します。これにより、一度に 1 つのプロセスのみがファイルを操作するため、同時実行性の問題が解決されます。

上記の内容は http://blog.csdn.net/daiyan_csdn/article/details/51524781 から参照しています

同時実行性が高い場合、同じファイルを操作するとデータの混乱が生じるため、ファイルに対していくつかの特別な処理が実行される必要があります。いくつかの解決策を以下にまとめます。

オプション 1: 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 を使用してロックするだけでは問題を完全に解決することはできません。

オプション 2: ロック時間を制限し、タイムアウトになったら終了

<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>
ログイン後にコピー
ログイン後にコピー

オプション 3: 一時ファイルを使用する

<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>
ログイン後にコピー
ログイン後にコピー

オプション 4: キューを使用する

ファイル操作用のキューを作成して書き込みますa スクリプトはファイル操作情報をキューから順番に読み取り、ファイルに対して対応する操作を実行します。これにより、一度に 1 つのプロセスのみがファイルを操作するため、同時実行性の問題が解決されます。

関連する推奨事項:

php での同時読み取りおよび書き込みファイルの競合の問題を解決する

以上がPHP でのファイルの同時読み取りと書き込みの問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート