ホームページ > バックエンド開発 > PHPチュートリアル > PHP_PHP チュートリアルで複数のユーザーが読み書きするときに空のファイルが発生する問題の解決策

PHP_PHP チュートリアルで複数のユーザーが読み書きするときに空のファイルが発生する問題の解決策

WBOY
リリース: 2016-07-13 10:47:07
オリジナル
1141 人が閲覧しました

其实解决多调用同时写一个文件时我们会使用flock来解决些问题,这样同一时间只有一个用户可以写文件,同时其它用户进行等待队列了,下面我来介绍一下flock解决多用户读写文件冲空问题


所以一般的方案会是:

 代码如下 复制代码

$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に設定されており、この時間内にロックが取得できなかった場合は、当然ながらファイルの操作権が得られるまで繰り返しロックが取得されます。タイムアウト制限に達した場合は、ただちに終了してロックを放棄し、他のプロセスが動作できるようにする必要があります。
解決策 2: flock 関数を使用せず、一時ファイルを使用して読み取りと書き込みの競合の問題を解決します。
一般原則は次のとおりです:
1.更新する必要があるファイルを一時ファイル ディレクトリに置き、ファイルの最終変更時刻を変数に保存し、この一時ファイルに繰り返しにくいランダムなファイル名を付けます。
2.この一時ファイルを更新した後、元のファイルの最終更新時刻が以前に保存した時刻と一致しているかどうかを確認します。
3.最終変更時刻が同じ場合、変更された一時ファイルの名前が元のファイルに変更されます。ファイルのステータスが同期して更新されるようにするには、ファイルのステータスをクリアする必要があります。
4.ただし、最終変更時刻が以前に保存された時刻と一致する場合は、この期間中に元のファイルが変更されたことを意味し、この時点で一時ファイルを削除する必要があり、他のプロセスが削除されていることを示す false が返されます。現時点ではファイルを操作しています。
おおよその実装コードは次のとおりです:

コードは次のとおりです コードをコピー

$dir_fileopen = "tmp";

関数randomid() {
戻り time().substr(md5(microtime()), 0, rand(5, 12));
}
関数 cfopen($filename, $mode) {
グローバル $dir_fileopen;
clearstatcache();
やります{
$id = md5(randomid(rand(), TRUE));
$tempfilename = $dir_fileopen."/".$id.md5($filename);
while(file_exists($tempfilename));
If (file_exists($filename)) {
$newfile = false;
copy($filename, $tempfilename);
}その他{
$newfile = true;
}
$fp = fopen($tempfilename, $mode);
$fp を返しますか? array($fp, $filename, $id, @filemtime($filename)) : false;
}
関数 cfwrite($fp,$string) { return fwrite($fp[0], $string) }
function cfclose($fp, $debug = "off") {
グローバル $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]);
}その他{
unlink($tempfilename);
//対象ファイルを操作している他のプロセスがあり、現在のプロセスが拒否されたことを示します
$success = false;
}
$success を返します;
}
$fp = cfopen('lock.txt','a+');
cfwrite($fp,"北京へようこそ.n");
fclose($fp,'on');


上記のコードで使用されている関数については、次のことを説明する必要があります:
1.rename(); ファイルまたはディレクトリの名前を変更するこの関数は、実際には Linux の mv に似ています。ファイルやディレクトリのパスや名前を更新すると便利です。
ただし、ウィンドウで上記のコードをテストすると、新しいファイル名がすでに存在する場合、現在のファイルがすでに存在するという通知が表示されます。ただし、Linux では正常に動作します。
2.clearstatcache(); ファイルのステータスをクリアします。PHP はパフォーマンスを向上させるためにすべてのファイル属性情報をキャッシュしますが、複数のプロセスがファイルを削除または更新している場合、PHP はキャッシュ内のファイル属性を更新する時間がない場合があります。 . 最終更新時刻へのアクセスが実際のデータではなくなる可能性があります。したがって、ここではこの関数を使用して保存されたキャッシュをクリアする必要があります。

オプション 3: 同時実行の可能性を減らすために、操作されたファイルをランダムに読み書きします。
このソリューションは、ユーザーのアクセス ログを記録するときによく使用されるようです。
以前は、ランダムなスペースを定義する必要がありました。スペースが大きいほど、同時実行の可能性は低くなります。ランダムな読み取りおよび書き込みスペースが [1 ~ 500] であるとすると、ログ ファイルの分布は log1 から log500 の範囲になります。ユーザーがアクセスするたびに、log1 ~ log500 までの任意のファイルにデータがランダムに書き込まれます。
同時に、2 つのプロセスがログを記録しています。プロセス A は更新された log32 ファイルである可能性がありますが、プロセス B はどうなるでしょうか。このときの更新は log399 になる可能性があります。プロセス B にも log32 を実行させたい場合、確率は基本的に 1/500 であり、ほぼゼロに等しいことを知っておく必要があります。
アクセスログを分析する必要がある場合、ここでは、最初にこれらのログをマージしてから分析するだけです。
このソリューションを使用してログを記録する利点の 1 つは、プロセス操作がキューに入れられる可能性が比較的小さく、プロセスが各操作を非常に迅速に完了できることです。

オプション 4: 操作するすべてのプロセスをキューに入れます。次に、ファイル操作を完了するための専用サービスを配置します。
キュー内の除外された各プロセスは最初の特定の操作に相当するため、ここに多数のファイル操作プロセスがある場合、初めてサービスはキューから特定の操作アイテムを取得するだけで済みます。列の最後尾に並んでください。列に並ぶ意思がある限り、列の長さは関係ありません。

前述のオプションには、それぞれ独自の利点があります。大きく分けて2つのカテゴリーに分かれます
1.オプション 1、2、4 などのキューに入れる必要がある (影響は遅い)
2.並ぶ必要はありません。 (ファストインパクト) オプション 3
キャッシュ システムを設計する場合、通常、オプション 3 は採用しません。案3の解析プログラムと書き込みプログラムは同期していないため、書き込みの際に解析の難易度は全く考慮されず、書き込みがよければ問題ありません。想像してみてください。キャッシュの更新時にランダムなファイルの読み書きも行うと、キャッシュの読み込み時に多くの処理が追加されそうです。ただし、オプション 1 と 2 はまったく異なりますが、書き込み時間はかかりますが (ロックの取得に失敗した場合は繰り返し取得されます)、ファイルの読み取りは非常に便利です。キャッシュを追加する目的は、データ読み取りのボトルネックを軽減し、それによってシステムのパフォーマンスを向上させることです。

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/632899.html技術記事実際、ファイルを書き込むために複数の呼び出しが同時に行われる場合、flock を使用していくつかの問題を解決します。これにより、他のユーザーがキューで待機している間、同時に 1 人のユーザーだけがファイルを書き込むことができます。 ..
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート