Dieses Mal werde ich Ihnen eine Analyse der Betriebsschritte der hohen gleichzeitigen Verarbeitung von PHP-Lese- und Schreibdateien geben. Was sind die Vorsichtsmaßnahmen für die hohe Parallelität der Verarbeitung von PHP-Lese- und Schreibdateien? Das Folgende ist ein praktischer Fall.
Seit kurzem muss die Spieleentwicklung des Unternehmens die Abwanderungsrate beim Laden von Spielen kennen. Weil wir Webspiele machen. Jeder, der schon einmal Webspiele gespielt hat, weiß, dass man einige Ressourcen laden muss, bevor man mit dem Spiel beginnen kann. Schließlich gelangen Sie zur Spieloberfläche zum Erstellen eines Charakters. Eine unserer Anforderungen besteht darin, die Anzahl der Benutzer zu zählen, die verloren gehen, bevor während des Ladevorgangs die Benutzeroberfläche zur Charaktererstellung erreicht wird. Wir zählen die Anzahl der Personen zu Beginn des Ladevorgangs und erfassen dann die Anzahl der Personen, nachdem der Ladevorgang abgeschlossen ist. Auf diese Weise wird die Anzahl der Personen nach erfolgreicher Verladung von der Anzahl der Personen vor der Verladung abgezogen. Kennen Sie einfach die Abwanderungsrate beim Laden. Sie können erkennen, ob das Spiel den Ladevorgang weiter optimieren und die Benutzerladerate des Spiels reduzieren muss. Weil unser Traffic aus den meisten Mainstream-Kooperationsmedien importiert wird. Daher ist die Parallelität sehr hoch und sollte nach groben Berechnungen etwa 1.000 Parallelitäten pro Sekunde erreichen können. Die Anzahl der Personen vor dem Laden sollte ursprünglich auf der Caching-Plattform im Spiel platziert werden. Die Kollegen im Spiele-Backend befürchten jedoch, dass die Parallelität zu hoch ist und unnötige Ressourcenverschwendung entsteht. Weil auf die Speicherfreigabe nicht in Echtzeit reagiert wird. Legen Sie daher die gezählte Personenzahl auf einen anderen Server: den Statistikserver. Die Lösung, die ich gerade verwendet habe, ist wie folgt: Durch PHPs<a href="http://www.php.cn/wiki/1311.html" target=" _blank">file_get_contents<p style="text-align: left;">()</p></a>
und <a href="http://www.php.cn/wiki/1312.html" target="_blank">file_put_contents<code><a href="http://www.php.cn/wiki/1311.html" target="_blank">file_get_contents</a>()
( ) Lesen und schreiben. Schreiben Sie beim ersten Lesen und Schreiben 1 in die Datei, fügen Sie beim zweiten Laden 1 zum Original hinzu und so weiter. Mit dieser Ideenfolge gibt es kein Problem. Das Problem liegt darin, dass unser Server nicht sequentiell sein kann. <a href="http://www.php.cn/wiki/1312.html" target="_blank">file_put_contents</a>()
Um genau zu sein, ist der gleichzeitige Zugriff nicht sequentiell. Wenn Spieler A das Spiel lädt und die Zahl 100 in der Datei liest (vorausgesetzt, es ist zu diesem Zeitpunkt 100), liest Spieler B auch 100. Zu diesem Zeitpunkt addiert der Thread verarbeitende Spieler A 1 zu 100, um 101 zu erhalten. wird 101 schreiben zur Datei. Der Thread-Verarbeitungsspieler B erhält ebenfalls das gleiche Ergebnis und schreibt 101 in die Datei. Zu diesem Zeitpunkt tritt das Problem auf? Spieler B hat das Spiel nach Spieler A geladen, daher sollte er ein Berechnungsergebnis von 102 erhalten. Dies ist das Problem, das durch Parallelität verursacht wird. Zu diesem Zeitpunkt dachte ich darüber nach, die Datei mit zu öffnen und mit fopen()
eine Schreibsperre hinzuzufügen. Jeder wird definitiv denken, dass es keine Probleme verursachen wird, wenn diese Methode gesperrt ist. Tatsächlich ist es auch falsch. flock()
auf das Array klicken, um zu erfahren, wie viele Spieler das Spiel geladen haben. count()
Die endgültige mögliche Lösung lautet wie folgt:
Verwenden Sie fopen, um eine Datei im schreibgeschützten Modus zu öffnen. Dann Schreibsperre. Jedes Mal, wenn ein Spieler lädt, schreibe ich eine Zahl 1 in die Datei. Der endgültige Dateiinhalt wird sofort über ausgelesen und dann wird die Länge mit file_get_contents()
berechnet, um zu erfahren, wie viele Spieler das Spiel geladen haben. strlen()
gesperrt wird, was dazu führt, dass die Systemressourcen für lange Zeit ansteigen. Daher habe ich die von allen verwendete Methode übernommen und die Mikrosekunden-Timeout-Technologie verwendet, um dieses Problem zu lösen. Wenn ich aus dieser Zeit herauskomme, werde ich es wegwerfen. Der spezifische Code lautet wie folgt: flock()
// loadcount.func.php 函数文件。 /** * 获取某来源和某服务器ID的游戏加载次数。 * * @param string $fromid 来源标识。 * @param int $serverid 服务器ID编号。 * * @return int */ function getLoadCount($fromid, $serverid) { global $g_global; $serverid = (int) $serverid; $fromid = md5($fromid); $filename = $fromid . $serverid . '.txt'; $data = file_get_contents($filename); return strlen($data); } /** * 获取某来源所有服务器的游戏加载次数。 * * @param string $fromid 来源标识。 * * @return int */ function getAllLoadCount($fromid) { global $g_global; $fromid = md5($fromid); $count = 0; foreach (glob("{$fromid}*.txt") as $filename) { $file_content = file_get_contents($filename); $count += strlen($file_content); } return $count; } /** * 清空所有的加载数据。 * * @return void */ function clearLoadCount() { foreach (glob("*.txt") as $filename) { unlink($filename); } return true; } /** * 延迟更新游戏加载次数中间件。 * * 使用此函数来延迟更新数据,原理:当不足1000次的时候,不更新数据库,超过1000就更新到数据库里面去。 * * @param string $fromid 来源标识。 * @param int $serverid 服务器ID编号。 */ function delayAddLoadCount($fromid, $serverid) { // 使用MD5生成文件名记录缓存次数。 $fromid = md5($fromid); $filename = $fromid . $serverid . '.txt'; if($fp = fopen($filename, 'a')) { $startTime = microtime(); do { $canWrite = flock($fp, LOCK_EX); if(!$canWrite) { usleep(round(mt_rand(0, 100)*1000)); } } while ( ( !$canWrite ) && ( ( microtime()- $startTime ) < 1000 ) ); if ($canWrite) { fwrite($fp, "1"); } fclose($fp); } return true; }
< ?php /** * @describe 平台用户加载游戏次数统计接口入口。 * @date 2012.12.17 */ include_once './loadcount.func.php'; // 测试用。 // $_GET['fromid'] = '4399'; // $_GET['serverid'] = mt_rand(0, 5); // 添加加载次数。 if ( $_GET['action'] == 'addcount' ) { $fromid = $_GET['fromid']; // 来源标识。 $serverid = $_GET['serverid']; // 服务器ID编号。 $return = delayAddLoadCount($fromid, $serverid); $return = $return ? 1 : 0; ob_clean(); echo json_encode($return); exit; } // 取加载次数。 elseif ( $_GET['action'] == 'getcount' ) { $fromid = $_GET['fromid']; // 来源标识。 if ( !isset( $_GET['serverid'] ) ) // 有服务器编号 ID则取来源对应的服务器加载次数。 { $count = getAllLoadCount($fromid); } else // 加载对应来源的次数。 { $serverid = $_GET['serverid']; // 服务器ID编号。 $count = getLoadCount($fromid, $serverid); } ob_clean(); header('Content-Type:text/html;charset=UTF-8'); $serverid = strlen($serverid) ? $serverid : '无'; echo "来源:{$fromid},服务器ID:{$serverid},游戏加载次数:" . $count; exit; } // 清除加载次数。 elseif ( $_GET['action'] == 'clearcount' ) { header('Content-Type:text/html;charset=UTF-8'); $return = clearLoadCount(); if ($return) { echo "清除成功!"; } else { echo "清除失败!"; } }
PHP数据库操作之高并发实例
高并发下PHP写文件日志丢失
<?php /** * Created by PhpStorm. * User: andyfeng * Date: 2015/6/24 * Time: 13:31 */ class LogFileUtil { public static $fileHandlerCache; private static $initFlag = false; private static $MAX_LOOP_COUNT = 3; private static function init() { self::$initFlag = true; register_shutdown_function(array("LogFileUtil", "shutdown_func")); } /** * 输出到文件日志 * @param $filePath 文件路径 * @param $msg 日志信息 * @return int */ public static function out($filePath, $msg) { if (!self::$initFlag) { self::init(); } return self::internalOut($filePath, $msg); } /** * @param $filePath * @param $msg * @param $loop * @return int */ private static function internalOut($filePath, $msg, $loop = 0) { //以防一直添加失败造成死循环 if ($loop > self::$MAX_LOOP_COUNT) { $result = 0; } else { $loop++; $fp = self::$fileHandlerCache["$filePath"]; if (empty($fp)) { $fp = fopen($filePath, "a+"); self::$fileHandlerCache[$filePath] = $fp; } if (flock($fp, LOCK_EX)) { $result = fwrite($fp, $msg); flock($fp, LOCK_UN); } else { $result = self::internalOut($filePath, $msg, $loop); } } return $result; } function shutdown_func() { if (!empty(LogFileUtil::$fileHandlerCache)) { if (is_array(LogFileUtil::$fileHandlerCache)) { foreach (LogFileUtil::$fileHandlerCache as $k => $v) { if (is_resource($v)) //file_put_contents("close.txt",$k); fclose($v); } } } } }
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Das obige ist der detaillierte Inhalt vonAnalyse der Verarbeitungsschritte mit hoher Parallelität beim Lesen und Schreiben von PHP-Dateien. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!