簡體   English   中英

PHP 中變量擴展與 sprintf 的性能

[英]Performance of variable expansion vs. sprintf in PHP

關於性能,執行以下操作有什么區別:

$message = "The request $request has $n errors";

$message = sprintf('The request %s has %d errors', $request, $n);

在 PHP 中?

我會說調用函數涉及更多的東西,但我不知道 PHP 在幕后做了什么來擴展變量名稱。

謝謝!

沒關系。

任何性能提升都將如此微不足道,以至於您只會在 10000 或 100000 次迭代中看到它(作為數百秒的改進)——即使如此。

有關具體數字,請參閱此基准測試 您可以看到它必須使用 100,000 次函數調用生成 1MB 以上的數據,才能在數百毫秒內實現可測量的差異。 幾乎沒有現實生活中的情況。 即使是最慢的方法(“帶有位置參數的 sprintf()”)也只需要 0.00456 毫秒,而最快的方法則需要 0.00282 毫秒。 對於需要 100,000 次字符串輸出調用的任何操作,您將有其他因素(例如網絡流量),這些因素將比您通過優化可以節省的 100 毫秒慢一個數量級。

使用任何使您的代碼對您和其他人來說最易讀和最易於維護的東西。 對我個人而言, sprintf()方法是一個不錯的主意 - 我必須考慮自己開始使用它。

在所有情況下,第二個都不會更快,因為您提供了一個雙引號字符串,它也必須被解析為變量。 如果您要進行微優化,正確的方法是:

$message = sprintf('The request %s has %d errors', $request, $n);

盡管如此,我相信秒數更慢(因為@Pekka 指出差異實際上並不重要),因為函數調用、解析字符串、轉換值等的開銷。但是請注意,2 行代碼不是等效,因為在第二種情況下 $n 被轉換為整數。 如果 $n 是“無錯誤”,那么第一行將輸出:

The request $request has no error errors

而第二個將輸出:

The request $request has 0 errors

有關“變量擴展與sprintf的”性能分析作出這里

正如@pekka 所說,“使您的代碼對您和其他人來說最具可讀性和可維護性”。 當性能增益“低”(~ 少於兩倍)時,忽略它。

總結基准:PHP 針對雙引號和 Heredoc 分辨率進行了優化。 尊重平均時間的百分比,僅使用計算一個很長的字符串,

  • 雙引號分辨率:75%
  • 遺傳分辨率:82%
  • 單引號連接:93%
  • sprintf 格式:117%
  • 帶有索引參數的 sprintf 格式:133%

請注意,只有 sprintf 執行一些格式化任務(請參閱基准測試的“%s%s%d%s%f%s”),並且正如@Darhazer 所示,它對輸出有一些影響。 更好的測試是兩個基准測試,一個只比較連接時間('%s' 格式化程序),其他包括格式化過程 - 例如 '%3d%2.2f' 和將變量擴展為雙引號之前的功能等價物......還有更多使用短模板字符串的基准組合。

優缺點

sprintf的主要優點是,如基准測試所示,非常低成本的格式化程序(!)。 對於通用模板,我建議使用vsprintf函數。

雙引號(和heredoc)的主要優點是一些性能; 以及與 sprintf 的位置標記相比,名義占位符的一些可讀性和可維護性,隨着參數數量的增加(1 之后)。

索引占位符的使用是 sprintf 可維護性的一半。

注意:不要使用單引號連接,只有在真正需要時才使用。 請記住,PHP 啟用了安全語法,例如"Hello {$user}_my_brother!" , 以及諸如"Hello {$this->name}!"類的引用 .

對於將多個字符串變量注入一個字符串,第一個會更快。

$message = "The request $request has $n errors";

對於單次注入,dot(.) 連接會更快。

$message = 'The request '.$request.' has 0 errors';

用十億循環進行迭代並找到差異。

例如:

<?php

    $request = "XYZ";
    $n = "0";
    $mtime = microtime(true);
    for ($i = 0; $i < 1000000; $i++) {
            $message = "The request {$request} has {$n} errors";
    }
    $ctime = microtime(true);
    echo ($ctime-$mtime);

?>

我很驚訝,但對於 PHP 7.* “$variables replacement” 是最快的方法

$message = "The request {$request} has {$n} errors";

你可以簡單地自己證明一下:

$request = "XYZ";
$n = "0";
$mtime = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
        $message = "The request {$request} has {$n} errors";
}
$ctime = microtime(true);
echo '

"variable $replacement timing": '.  ($ctime-$mtime);




$request = "XYZ";
$n = "0";
$mtime = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
        $message = 'The request '.$request.' has '.$n.' errors';
}
$ctime = microtime(true);
echo '

"concatenation" . $timing: '.  ($ctime-$mtime);



$request = "XYZ";
$n = "0";
$mtime = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
        $message = sprintf('The request %s has %d errors', $request, $n);
}
$ctime = microtime(true);
echo '

sprintf("%s", $timing): '.  ($ctime-$mtime);

PHP 7.3.5的結果:

“變量 $replacement 時間”:0.091434955596924

“串聯”。 $時間:0.11175799369812

sprintf("%s", $timing): 0.17482495307922

可能您已經找到了諸如“使用 sprintf 而不是包含在雙引號中的變量,它的速度大約快 10 倍”之類的建議。 有哪些好的 PHP 性能技巧?

我明白這是事實,但有一天。 PHP 5.2.* 之前

以下是當時PHP 5.1.6的示例:

“變量 $replacement 時間”:0.67681694030762

“串聯”。 $時間:0.24738907814026

sprintf("%s", $timing): 0.61580610275269

最終,在考慮單個變量賦值的上下文時,第一個是最快的,這可以通過查看各種基准來看到。 也許,使用核心 PHP 函數的 sprintf 風格可以允許更多可擴展的代碼,並更好地優化字節碼級緩存機制,如 opcache 或 apc。 換句話說,特定大小的應用程序在使用 sprintf 方法時可以使用更少的代碼。 您需要緩存到 RAM 中的代碼越少,用於其他事物或更多腳本的 RAM 就越多。 但是,這僅在您的腳本無法使用評估正確放入 RAM 時才重要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM