在進行數值計算密集型操作時,即使是諸如cosh()這樣的標準數學函數,也可能成為性能瓶頸的來源。 cosh ()是php中計算雙曲餘弦的內置函數,廣泛用於物理模擬、金融建模或其他科學計算中。當它在循環中被頻繁調用時,就有可能出現性能下降的問題。 ,就有可能出現性能下降的問題。
本文將以cosh()函數為例,分析在php中如何排查性能瓶頸,並給出相應的優化建議。 ,並給出相應的優化建議。
sicrime(true)對循環進行包裹,測量函數運行前後時間差。例如::
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-variable">$start</span></span><span> = </span><span><span class="hljs-title function_ invoke__">microtime</span></span><span>(</span><span><span class="hljs-literal">true</span></span><span>);
</span><span><span class="hljs-keyword">for</span></span><span> (</span><span><span class="hljs-variable">$i</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span> < </span><span><span class="hljs-number">1000000</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span>++) {
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">cosh</span></span><span>(</span><span><span class="hljs-variable">$i</span></span><span> * </span><span><span class="hljs-number">0.0001</span></span><span>);
}
</span><span><span class="hljs-variable">$end</span></span><span> = </span><span><span class="hljs-title function_ invoke__">microtime</span></span><span>(</span><span><span class="hljs-literal">true</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"执行时间: "</span></span><span> . (</span><span><span class="hljs-variable">$end</span></span><span> - </span><span><span class="hljs-variable">$start</span></span><span>) . </span><span><span class="hljs-string">" 秒"</span></span><span>;
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
通過這種方式可以初步判斷是否cosh()函數成為了主要的性能消耗源。
Xdebug php的強大調試和性能分析工具,通過它配合webgrind或QCachegrind,可以詳細分析函數調用的耗時。
安裝完xdebug後,開啟性能分析::
<span><span><span class="hljs-attr">xdebug.mode</span></span><span>=profile
</span><span><span class="hljs-attr">xdebug.output_dir</span></span><span>=</span><span><span class="hljs-string">"/tmp"</span></span><span>
</span></span>
運行目標腳本後,會生成。
更多信息可以參考: https://gitbox.net/docs/php-xdebug-profiler-usage
如果你運行的是長時間執行的php 腳本(如(cli)( cli任務) ,可以使用頂htop,
如果cosh()函數的參數是重複的或可以被緩存,可以使用數組緩存其結果,避免重複計算::
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-variable">$cache</span></span><span> = [];
</span><span><span class="hljs-keyword">for</span></span><span> (</span><span><span class="hljs-variable">$i</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span> < </span><span><span class="hljs-number">1000000</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span>++) {
</span><span><span class="hljs-variable">$arg</span></span><span> = </span><span><span class="hljs-variable">$i</span></span><span> * </span><span><span class="hljs-number">0.0001</span></span><span>;
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-keyword">isset</span></span><span>(</span><span><span class="hljs-variable">$cache</span></span><span>[</span><span><span class="hljs-variable">$arg</span></span><span>])) {
</span><span><span class="hljs-variable">$cache</span></span><span>[</span><span><span class="hljs-variable">$arg</span></span><span>] = </span><span><span class="hljs-title function_ invoke__">cosh</span></span><span>(</span><span><span class="hljs-variable">$arg</span></span><span>);
}
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-variable">$cache</span></span><span>[</span><span><span class="hljs-variable">$arg</span></span><span>];
}
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
對於一些應用場景,特別是圖形渲染或實時性要求較高的系統,可以考慮用雙曲餘弦的泰勒級數近似實現來替代內置函數。 ,可以考慮用雙曲餘弦的泰勒級數近似實現來替代內置函數。
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">cosh_approx</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$x</span></span></span><span>, </span><span><span class="hljs-variable">$terms</span></span><span> = </span><span><span class="hljs-number">5</span></span><span>) {
</span><span><span class="hljs-variable">$sum</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>;
</span><span><span class="hljs-keyword">for</span></span><span> (</span><span><span class="hljs-variable">$n</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>; </span><span><span class="hljs-variable">$n</span></span><span> < </span><span><span class="hljs-variable">$terms</span></span><span>; </span><span><span class="hljs-variable">$n</span></span><span>++) {
</span><span><span class="hljs-variable">$sum</span></span><span> += </span><span><span class="hljs-title function_ invoke__">pow</span></span><span>(</span><span><span class="hljs-variable">$x</span></span><span>, </span><span><span class="hljs-number">2</span></span><span> * </span><span><span class="hljs-variable">$n</span></span><span>) / </span><span><span class="hljs-title function_ invoke__">gmp_intval</span></span><span>(</span><span><span class="hljs-title function_ invoke__">gmp_fact</span></span><span>(</span><span><span class="hljs-number">2</span></span><span> * </span><span><span class="hljs-variable">$n</span></span><span>));
}
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$sum</span></span><span>;
}
</span></span>
注意這種方式適用於參數範圍較小的情形,且結果精度需評估。 ,且結果精度需評估。
在cli環境中,如果要並行處理大量數據,可以使用pcntl_fork()或者parallel擴展進行任務並發,提升整體吞吐量。例如:::
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-variable">$processes</span></span><span> = </span><span><span class="hljs-number">4</span></span><span>;
</span><span><span class="hljs-variable">$segment</span></span><span> = </span><span><span class="hljs-number">250000</span></span><span>;
</span><span><span class="hljs-keyword">for</span></span><span> (</span><span><span class="hljs-variable">$i</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span> < </span><span><span class="hljs-variable">$processes</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span>++) {
</span><span><span class="hljs-variable">$pid</span></span><span> = </span><span><span class="hljs-title function_ invoke__">pcntl_fork</span></span><span>();
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$pid</span></span><span> === </span><span><span class="hljs-number">0</span></span><span>) {
</span><span><span class="hljs-keyword">for</span></span><span> (</span><span><span class="hljs-variable">$j</span></span><span> = </span><span><span class="hljs-variable">$i</span></span><span> * </span><span><span class="hljs-variable">$segment</span></span><span>; </span><span><span class="hljs-variable">$j</span></span><span> < (</span><span><span class="hljs-variable">$i</span></span><span> + </span><span><span class="hljs-number">1</span></span><span>) * </span><span><span class="hljs-variable">$segment</span></span><span>; </span><span><span class="hljs-variable">$j</span></span><span>++) {
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">cosh</span></span><span>(</span><span><span class="hljs-variable">$j</span></span><span> * </span><span><span class="hljs-number">0.0001</span></span><span>);
}
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
}
</span><span><span class="hljs-keyword">while</span></span><span> (</span><span><span class="hljs-title function_ invoke__">pcntl_waitpid</span></span><span>(</span><span><span class="hljs-number">0</span></span><span>, </span><span><span class="hljs-variable">$status</span></span><span>) !== -</span><span><span class="hljs-number">1</span></span><span>);
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
對於極限性能需求,可以考慮將部分計算用c編寫為擴展模塊,或使用php 7.4+的ffi功能,調用外部的高性能數學庫。 ,調用外部的高性能數學庫。
更多示例詳見https://gitbox.net/articles/php-ffi-performance-math
雖然php並非為高性能科學計算設計,但通過合理的優化策略,仍然可以在某些場景下發揮其潛力。在使用如cosh()這類數學函數進行大規模循環計算時