PHP程序應該減少brk調(diào)用,否則性能會受影響

昨天工作上遇到一個非常有意思的問題,特此分享給大家,也給大家提個醒,在 PHP 程序中盡量減少系統(tǒng)調(diào)用。在我們系統(tǒng)中有一個 cron 腳本,完成的主要工作就是從 memcached 中獲取數(shù)據(jù),然后同步到數(shù)據(jù)庫中。平時運行的好好的,但昨天卻遇到了問題,唯一的變化就是本次任務從 memcached 中獲取的數(shù)據(jù)非常多,總共有 100 萬條記錄。話不多少,先上偽代碼:

//共100萬個memcached數(shù)據(jù)
$tnum = 1000000;
//共1萬個key,每個100條memcached數(shù)據(jù)
$knum = ceil($tnum/100);
$mem->connect("localhost", "11211");

for ($i = 1; $i <= $knum; $i++) 
    $k[] = $mckey."_".$i;

# 一次性從 memcached 中獲取到數(shù)據(jù)
$emailmc = $mem->get($k);

$email = array();
foreach ($emailmc as $v) {
    $s     = unserialize($v);
    $s     = explode(",", $s);
    # 合并數(shù)組
    $email = array_merge($email, $s);
}

# 一次性導入到 mecached 中
importdb($email);

彪悍的 memcached

由于腳本本次運行對業(yè)務非常重要,我一直在監(jiān)視,發(fā)現(xiàn)運行了半個小時也沒有結(jié)束,開始我思索是不是memcached一次性獲取太多了,導致memcached查詢遇到問題了?

使用 wireshark 和 strace 抓取了相關數(shù)據(jù),發(fā)現(xiàn)獲取 memcached 非???,幾秒鐘就返回了,贊一下 memcached 性能。

brk

接下去繼續(xù)分析,strace 出現(xiàn)了滿屏的 brk 系統(tǒng)調(diào)用,如下:

$ strace -p 27429 -T
brk(0x6d4c000)                          = 0x6d4c000 <0.000007>
brk(0x6d8c000)                          = 0x6d8c000 <0.000007>
brk(0x6dcc000)                          = 0x6dcc000 <0.000007>
brk(0x6e0c000)                          = 0x6e0c000 <0.000007>
brk(0x6e4c000)                          = 0x6e4c000 <0.000006>

雖然每次的 brk 調(diào)用響應并不慢,但次數(shù)太多了,那么到底什么是 brk?

brk, sbrk - change data segment size

也就是說 brk 在不斷的改變某個指針對象的內(nèi)容,按照上面的偽代碼,email 變量不斷的在調(diào)整內(nèi)存大小,而且email 變量的內(nèi)存越來越大,執(zhí)行速度也越來越慢,而且執(zhí)行到一定時間,php出現(xiàn)了內(nèi)存不夠的錯誤,我做了相關調(diào)整:

ini_set('memory_limit', '500M');
$email = array();
foreach ($emailmc as $v) {
    $s     = unserialize($v);
    $s     = explode(",", $s);
    $email = array_merge($email, $s);
    echo memory_get_usage();
}

memory_limit 是限制 php 程序能夠使用的內(nèi)存大小,通過 memory_get_usage 函數(shù)發(fā)現(xiàn),內(nèi)存使用越來越大,雖然最后代碼也能夠運行,但卻要花費至少半個小時。

call_user_func_array

對于 php 程序來說,應用代碼是涉及不到 brk 調(diào)用的,但如果能夠減少調(diào)用,程序執(zhí)行時間肯定會提高很多,現(xiàn)在的目的就是減少 array_merge 操作,我先修改了部分代碼,分批次從 memcached 中獲?。?/p>

//共100萬個memcached數(shù)據(jù)
$tnum = 1000000;
//共1萬個key,每個100條memcached數(shù)據(jù)
$knum = ceil($tnum/100);
$mem->connect("localhost", "11211");

$j = 1;
for ($i = 1; $i <= $knum; $i++) {
    $k[] = $mckey."_".$i;
    if (count($k)>100) {
        $emailmc = $mem->get($k);
        foreach ($emailmc as $v) {
            $s     = unserialize($v);
            $s     = explode(",", $s);
            $emailarr[$j] = $s;
            $j++;
        }
        $k = array();
    }
}

# 要運行 100 次
for ($i=1;$i<=$j;$i++) {
    $email = array_merge($email,$emailarr[$j]);
}
importdb($email);

我分批次從 memcached 中獲取數(shù)據(jù),然后保存到 $emailarr 數(shù)組變量中,如果再循環(huán) array_merge,雖然速度快了一些,但仍然要100次,運行速度仍然非常慢。

我思索是不是在 php 內(nèi)部能夠?qū)?$emailarr 數(shù)組一次性合并呢?雖然有思路,但不知道具體如何操作,咨詢了 php 大牛,提出了 call_user_func_array 函數(shù)。

修改如下:

$email = call_user_func_array('array_merge', $email);
importdb($email);

代碼居然2秒就返回了,避免了由 php 應用代碼進行大量的 array_merge 合并,由 php 內(nèi)部一次性完成了 array_merge。

可能有些同學說,為啥你不能從 memcached 中獲取一部分數(shù)據(jù)就導入到數(shù)據(jù)庫中呢?主要原因是后面代碼太復雜,怕出現(xiàn)新的問題,所以本次的改造思路就是一次性獲取到 $email 變量對應的數(shù)據(jù)。

總結(jié):php 應用代碼不會和系統(tǒng)調(diào)用直接產(chǎn)生聯(lián)系,可系統(tǒng)調(diào)用非常昂貴,應該減少調(diào)用,所以在開發(fā)的時候,應該想象下php代碼的運行邏輯,從而提升性能。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 關于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,300評論 2 89
  • 1、memcache的概念? Memcache是一個高性能的分布式的內(nèi)存對象緩存系統(tǒng),通過在內(nèi)存里維護一個統(tǒng)一的巨...
    桖辶殤閱讀 2,358評論 2 12
  • 分類:人們最容易花錢的心理賬戶——意外所得賬戶,也就是常說的“來得容易去得快”;情感維系賬戶,也就是常說的“談感情...
    葛貓咪0527閱讀 397評論 0 0
  • 有些女生,她沒心沒肺的,不曾喜歡過別人,小說里的青春情節(jié)與她無關,一切用她自己的話來講就是懶,懶得去照顧另一...
    梁重吾閱讀 585評論 0 0

友情鏈接更多精彩內(nèi)容