Detailed Explanation of PHP High Concurrent Processing Operation Example for Reading and Writing Files

  • 2021-09-16 06:29:41
  • OfStack

In this paper, an example is given to describe the high concurrent processing operation of PHP reading and writing files. Share it for your reference, as follows:

Background:

Recently, company game development needs to know the churn rate of game loading. Because, what we do is web games. Anyone who has played web games knows that 1 resource should be loaded before entering the game. Finally, you can reach the game interface for creating characters. We have a requirement to count the number of users who have not reached the role creation interface during the loading process.

We count the number of people at the beginning of loading, and record the number of people after loading. In this way, by subtracting the number of people after successful loading from the number of people before loading. You know the churn rate of loading. You can know whether the game should continue to optimize the loading process and reduce the user loading rate of the game.

Because, our quantity is from * the mainstream cooperative media to guide the quantity. Therefore, the concurrency is very high, and according to rough calculation, it should reach about 1000 concurrency per second.

The number of people before loading was originally intended to be placed on the cache platform inside the game. However, colleagues at the back end of the game are worried that the concurrency is too high, resulting in unprovoked waste of resources. Because the release of memory is not responsive in real time. Therefore, put the counted number on another server: the statistics server.

The scheme I started with is as follows:

Through php's file_get_contents() And file_put_contents() Read and write. Write 1 to the file on the first read and write, add 1 to the original on the second load, and so on. There is no problem with this idea of sequence at all. The problem is that our servers can't be sequential.

To be precise, concurrent access is not sequential. When the A player loads the game and reads the number 100 in the file (if it is 100 at this time), the B player reads 100, at this time, the thread processing the A player is adding 1 on the basis of 100, getting 101, and writing 101 to the file.

Threads that process B players get the same result, writing 101 to a file. At this time, the problem arises? The B player loads the game after the A player and deserves 102.

This is the problem caused by concurrency. At this time, I thought of adopting fopen() Open the file and use the flock() Add 1 write lock. Everyone 1 will think that if this way is locked, it will not cause problems. In fact, it is also wrong.

Because, our problem is not writing. But the data is out of sync when reading. OK. Here, I really can't handle Baidu and Google.

When hopes are pinned on the PHP function itself and dreams are broken, I can only find another way. Get out of it. So, I thought of the mechanism of Map mapping of * language. Similar to our PHP array, I add one element to the array every time I load it. In this way, in the end, all I need is count() 1 below the array to know how many players loaded the game.

However, with arrays, there is also a problem. Is PHP variables or constants, in the script after the completion of their own clear. So, I thought of the way to save files.

The final feasible scheme is as follows:

Open a file with fopen in a write-only manner. Then write the lock. Every time the player loads, I write a number 1 to the file, and the final file content passes through file_get_contents() Read it out once, and then use it strlen() Calculate the length of 1 to know how many players have loaded the game.

Hear flock() Function will lock, which will cause system resources to rise for a lot of time. Therefore, I use the method that everyone uses to solve this problem with microsecond timeout technology. If I get out of this time, I will * drop it. The specific code is as follows:


// loadcount.func.php  Function file. 
/**
 *  Get a source and a server ID The number of times the game is loaded. 
 *
 * @param string $fromid  Source identification. 
 * @param int $serverid  Server ID Number. 
 *
 * @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);
}
/**
 *  Gets the number of games loaded on all servers from a source. 
 *
 * @param string $fromid  Source identification. 
 *
 * @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;
}
/**
 *  Empty all load data. 
 *
 * @return void
 */
function clearLoadCount()
{
    foreach (glob("*.txt") as $filename) {
      unlink($filename);
    }
    return true;
}
/**
 *  Delayed update of game load times middleware. 
 *
 *  Use this function to delay updating data. Principle: When insufficient 1000 The database is not updated, exceeding 1000 Update it to the database. 
 *
 * @param string $fromid  Source identification. 
 * @param int $serverid  Server ID Number. 
 */
function delayAddLoadCount($fromid, $serverid)
{
    //  Use MD5 Generate file name record cache times. 
    $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;
}

The following is the file where I called the above methods:


< ?php
/**
 * @describe  Platform users load game statistics interface entry. 
 * @date 2012.12.17
 */
include_once './loadcount.func.php';
//  For testing. 
// $_GET['fromid']  = '4399';
// $_GET['serverid'] = mt_rand(0, 5);
//  Add the number of loads. 
if ( $_GET['action'] == 'addcount' )
{
    $fromid  = $_GET['fromid'];  //  Source identification. 
    $serverid = $_GET['serverid']; //  Server ID Number. 
    $return = delayAddLoadCount($fromid, $serverid);
    $return = $return ? 1 : 0;
    ob_clean();
    echo json_encode($return);
    exit;
}
//  Take the number of loads. 
elseif ( $_GET['action'] == 'getcount' )
{
    $fromid = $_GET['fromid'];  //  Source identification. 
    if ( !isset( $_GET['serverid'] ) ) //  There is a server number  ID Then take the server loading times corresponding to the source. 
    {
        $count = getAllLoadCount($fromid);
    }
    else //  The number of times the corresponding source is loaded. 
    {
        $serverid = $_GET['serverid']; //  Server ID Number. 
        $count = getLoadCount($fromid, $serverid);
    }
    ob_clean();
    header('Content-Type:text/html;charset=UTF-8');
    $serverid = strlen($serverid) ? $serverid : ' None ';
    echo " Source :{$fromid}, Server ID:{$serverid}, Game loading times: " . $count;
    exit;
}
//  Clear the number of loads. 
elseif ( $_GET['action'] == 'clearcount' )
{
    header('Content-Type:text/html;charset=UTF-8');
    $return = clearLoadCount();
    if ($return)
    {
        echo " Clear successfully! ";
    }
    else
    {
        echo " Cleaning failed! ";
    }
}

This is the lesson of blood, so I have to record it. In case others learn from it in the future.

This article is the author Han Bing 1 year ago in 4455 miniclip game studio is responsible for doing data analysis when the code. I hope it will be helpful to everyone.

Highly concurrent instances of PHP database operations

Loss of PHP write file log under high concurrency


<?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"));
  }
  /**
   *  Output to file log 
   * @param $filePath  File path 
   * @param $msg  Log information 
   * @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) {
    // In case 1 Direct Add Failure Causes Infinite Loop 
    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);
        }
      }
    }
  }
}

For more readers interested in PHP related contents, please check the topics on this site: "php File Operation Summary", "php Cache Technology Summary", "PHP Operation and Operator Usage Summary", "PHP Basic Syntax Introduction Course", "php Object-Oriented Programming Introduction Course", "php String Usage Summary", "php+mysql Database Operation Introduction Course" and "php Common Database Operation Skills Summary"

I hope this article is helpful to everyone's PHP programming.


Related articles: