在进行数值计算密集型操作时 在进行数值计算密集型操作时, 即使是诸如cosh ()这样的标准数学函数, 也可能成为性能瓶颈的来源。 cosh ()是 php 中计算双曲余弦的内置函数, 广泛用于物理模拟、金融建模或其他科学计算中。当它在循环中被频繁调用时, 就有可能出现性能下降的问题。
本文将以cosh () osh osh , 分析在 php 中如何排查性能瓶颈, 并给出相应的优化建议。
MICROTIME (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 () osh
xdebug ug 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>
运行目标脚本后 运行目标脚本后, 会生成.cachegrind文件 文件, 然后通过 webgrind 打开分析, 查看cosh ()函数在整个调用栈中所占时间比例。
: ~ https://gitbox.net/docs/php-xdebug-profiler-usage
如果你运行的是长时间执行的 php 脚本 ay (如 如 cli 任务), 可以使用상단 、 htop等命令实时查看 php 进程的 cpu 和内存使用状况。也可以在脚本中使用memory_get_usage ()进行内存快照记录。
如果cosh () osh osh, 可以使用数组缓存其结果, 避免重复计算 : :
<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 ()或者평행扩展进行任务并发, 提升整体吞吐量。例如 : :
<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 ()这类数学函数进行大规模循环计算时 这类数学函数进行大规模循环计算时, 务必借助性能分析工具找出瓶颈, 并采用缓存、并行处理或本地扩展等方式加以优化。这样既能提升运行效率, 又能保持代码的可维护性与稳定性。 又能保持代码的可维护性与稳定性。