[英]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 分辨率進行了優化。 尊重平均時間的百分比,僅使用計算一個很長的字符串,
請注意,只有 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.