一般的な解決策は次のとおりです:
コードをコピーします コードは次のとおりです:
$fp = fopen("/tmp/lock.txt", "w+");
if (flock($fp , LOCK_EX) ) {
fwrite($fp, "ここに何かを書き込んでください");
flock($fp, LOCK_UN);
} else {
echo "ファイルをロックできませんでした!";
}
fclose($fp );
しかし、PHP では flock はそれほどうまく機能しないようです。複数の同時実行の場合、リソースが独占されてすぐに解放されないか、まったく解放されないことが多く、デッドロックが発生し、サーバーの CPU 使用率が非常に高くなり、場合によってはサーバーが完全に停止することもあるようです。これは多くの Linux/UNIX システムで発生するようです。
したがって、flock を使用する前に、慎重に検討する必要があります。
解決策はないのでしょうか?実際にはそうではありません。 flock() を適切に使用すれば、デッドロックの問題を解決することは完全に可能です。もちろん、flock() 関数の使用を考慮しない場合でも、問題に対する適切な解決策はあります。
私の個人的な収集と要約を経て、解決策は大まかに次のようにまとめられます。
オプション 1: ファイルをロックするときにタイムアウトを設定します。
おおよその実装は次のとおりです:
コードをコピーします コードは次のとおりです:
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) if ($canWrite) {
fwrite($fp, $dataToSave);
}
fclose($fp) ;
}
タイムアウトは 1ms に設定されており、この時間内にロックが取得されなかった場合は、当然ファイルの操作権が得られるまで繰り返しロックが取得されます。タイムアウト制限に達した場合は、ただちに終了してロックを放棄し、他のプロセスが動作できるようにする必要があります。
オプション 2: 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));
$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] )||。 = cfopen('lock.txt','a+');
cfwrite($fp,"welcome to beijing.n");
fclose($fp,'on ');
上記のコードで使用されている関数について説明する必要があります:
1.rename(); この関数は実際には Linux の mv に似ています。ファイルやディレクトリのパスや名前を更新すると便利です。
しかし、ウィンドウで上記のコードをテストすると、新しいファイル名がすでに存在する場合、現在のファイルがすでに存在するという通知が表示されます。ただし、Linux では正常に動作します。
2.clearstatcache(); ファイルのステータスをクリアします。PHP はパフォーマンスを向上させるためにすべてのファイル属性情報をキャッシュしますが、複数のプロセスがファイルを削除または更新している場合、PHP はキャッシュ内のファイルを更新する時間がない場合があります。属性により、アクセスされた最終更新時刻が実際のデータではないという事実が簡単に発生する可能性があります。したがって、ここではこの関数を使用して保存されたキャッシュをクリアする必要があります。
オプション 3: 同時実行の可能性を減らすために、操作されたファイルをランダムに読み書きします。
このソリューションは、ユーザーのアクセス ログを記録するときによく使用されるようです。
以前は、ランダムなスペースを定義する必要がありました。スペースが大きいほど、同時実行の可能性は小さくなります。その場合、ログ ファイルの分布は 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 はまったく異なりますが、書き込み時間はかかりますが (ロックの取得に失敗した場合は繰り返し取得されます)、ファイルの読み取りは非常に便利です。キャッシュを追加する目的は、データ読み取りのボトルネックを軽減し、それによってシステムのパフォーマンスを向上させることです。
http://www.bkjia.com/PHPjc/825092.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/825092.html技術記事一般的な解決策は次のとおりです。 $fp = fopen("/tmp/lock.txt", "w+"); if (flock($fp, LOCK_EX)) { fwrite($fp, "ここに何か書きます"); flock($fp, LOCK_UN); } else...