国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - PHP教程 - PHP讀寫文件高并發處理操作實例詳解

PHP讀寫文件高并發處理操作實例詳解

2019-10-15 11:02coder狼 PHP教程

這篇文章主要介紹了PHP讀寫文件高并發處理操作,結合實例形式較為詳細的分析了php高并發訪問讀寫操作相關處理操作技巧,需要的朋友可以參考下

本文實例講述了PHP讀寫文件高并發處理操作。分享給大家供大家參考,具體如下:

背景:

最近公司游戲開發需要知道游戲加載的流失率。因為,我們做的是網頁游戲。玩過網頁游戲的人都知道,進入游戲前要加載一些資源。最后才能到達創建角色的游戲界面。我們有一個需求就是要統計在加載過程中還未到達角色創建界面而流失的用戶數量。

我們在加載開始就進行統計人數,加載完成之后再記錄人數。這樣,通過用加載前的人數減去成功加載后的人數。就知道了加載的流失率。就可以知道游戲是否還要繼續優化加載過程,降低用戶加載游戲率。

由于,我們的量都是從*主流的合作媒體進行導量過來。所以,并發非常高,據粗略計算應該能達到每秒1000左右的并發數量。

加載前的人數本來想放到游戲內部的緩存平臺。但是,游戲后端的同事擔心并發太高,導致資源無故浪費。因為,內存的釋放并不是實時響應的。所以,將統計的人數放到在另外一臺服務器:統計服務器。

我剛開始采用的方案如下:

通過php的file_get_contents()file_put_contents()進行讀取與寫入。第一次讀寫就向文件寫入1,第二次加載就在原來的基礎上加1.以此類推.這種順序的思想完全不存在任何問題。問題就出在,我們的服務器不可能是順序形式的。

準確的說,并發的訪問不是順序的。當A玩家加載游戲讀取到文件里面的數字100(假如這時是100),B玩家讀取到的也是100,這時,處理A玩家的線程就是在100的基礎上加1,得到101,就會向文件寫入101。

處理B玩家的線程也得到相同的結果,將101寫入文件。這時,問題就出現了?B玩家是在A玩家之后加載游戲的,理應得到102的計算結果。

這就是并發導致的問題。這個時候,我想到了采用fopen()打開文件,并用flock()加一個寫入鎖。大家一定會認為,這種方式有了鎖定,那么就不會造成問題了。其實,也是錯的。

因為,我們的問題不是出在寫入上面。而是讀取的時候造成數據的不同步。OK。到這里,我實在百度谷歌都搞不定了。

當希望寄托在PHP函數本身而夢碎的時候,我只能另尋它法。脫離它。于是,我想到了*語言的Map映射的機制。類似于我們的PHP數組,每加載一次就我往數組添加一個元素。這樣,到最后我只需要count()一下數組就知道了有多少玩家加載了游戲。

但是,用數組的話,也存在一個問題。就是PHP的變量還是常量,在腳本執行完畢之后都會自己清掉。于是,我想到了文件保存的方式。

最終的可行方案思路如下:

用fopen打開一個文件,以只寫的方式。然后寫鎖定。玩家每加載一次我就向文件里面寫入一個數字1,最后得到的文件內容通過file_get_contents()一次性讀取出來,再用strlen()計算一下長度即知道了有多少玩家加載了游戲。

聽聞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 "清除失敗!";
    }
}

這是血的教訓,所以,我不得不將它記錄下來。以備以后讓他人借鑒。

本文是作者寒冰一年前在4399游戲工作室負責做數據分析的時候寫的代碼。希望對大家有所幫助。

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程序設計有所幫助。

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 小视频在线 | 日本不卡一二三区 | 国产欧美日韩在线观看 | 51ⅴ精品国产91久久久久久 | 亚洲精品视频大全 | 日韩av一区二区在线观看 | 亚洲国产精品久久久 | 欧美日韩在线视频观看 | 久久成人18免费网站 | 久久精品成人一区二区三区蜜臀 | 亚洲精品一区二区三区在线 | 国产精品久久久久久久久福交 | 欧美久久久久久久 | 国产精品二区三区 | 国产欧美日韩综合精品一区二区 | 亚洲人成在线播放 | 欧洲一级毛片 | 亚洲成人一区二区三区 | 国产精品成人一区二区三区夜夜夜 | 国产精品一区久久 | 懂色av一区二区三区 | 久久午夜电影 | 国产一区日韩欧美 | 精品成人一区二区 | 欧洲一区在线 | 91激情视频 | 99re视频在线观看 | 久久久久综合精品福利啪啪 | 天天草夜夜| 国产精品第一区 | 精品三级三级三级三级三级 | 看一级黄色大片 | 欧美日韩国产一区二区三区 | 久久91精品国产 | www.亚洲 | 怡红院成人影院 | 1000部精品久久久久久久久 | 精品成人在线视频 | 美女国产精品 | 美女久久久久 | 毛片在线免费 |