PHP exec()性能

问题描述 投票:16回答:6

以下PHP代码确实返回了大约3.5秒的运行时间(多次测量并取平均值):

$starttime = microtime(true);
exec('/usr/local/bin/convert 1.pdf -density 200 -quality 85% 1.jpg');
$endtime = microtime(true);
$time_taken = $endtime-$starttime;

当我在ssh终端上运行相同的命令时,运行时间减少到大约0.6秒(使用命令行工具time测量)。

imagemagick库的版本是

Version: ImageMagick 6.7.0-10 2012-12-18 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2011 ImageMagick Studio LLC
Features: OpenMP

这个时差的原因是什么?

在stackoverflow上对类似问题的一个答案是,开销来自必须启动线程/ shell的Web服务器。这可能是真的吗?我认为线程是轻量级的,并且不需要花很长时间才能启动/终止。

在调用exec之前,我设置了imagemagick使用的线程数(因为这是/在OpenMP中的错误?,Reference)与exec('env MAGICK_THREAD_LIMIT=1');的1。无论我为MAGICK_THREAD_LIMIT设置什么值,PHP的运行时间都没有太大变化。无论如何,在这个版本中OpenMP上似乎没有错误,因为命令行执行的运行时是可以的。

任何关于如何改进上述命令的运行时间的建议将不胜感激。

非常感谢您的帮助。

php performance runtime exec
6个回答
4
投票

@Philipp因为你有SSH,并且由于你的服务器允许访问exec(),我将假设你也拥有对该机器的完全root访问权限。

建议用于单个文件处理

拥有对计算机的root权限意味着您可以更改/etc/php5/php.ini内存限制设置。

即使没有直接访问/etc/php5/php.ini,您也可以通过在项目目录中创建新的php.ini文件来检查您的服务器是否支持覆盖php.ini指令。

即使不允许覆盖,如果.htaccessAllowOverride,你也可以从All更改你的记忆设置。

另一种更改内存限制的方法是在PHP运行时使用ini_set('memory_limit', 256);设置它。

建议用于批处理文件处理

通过exec()运行转换的唯一好处是,如果您不打算从exec()获取结果并允许它以异步方式运行:

exec('convert --your-convert-options > /dev/null 2>/dev/null &');

如果您尝试批处理许多文件,上述方法通常很有用,您不希望等待它们完成处理,也不需要确认每个文件已经处理完毕。

表现说明

使用上面的代码使exec运行async来处理单个文件将比在PHP中使用GD / Imagick花费更多的处理器时间和更多的内存。时间/内存将由不影响PHP过程的不同进程使用(使访问者感觉网站移动得更快),但存在内存消耗,以及处理许多将计数的连接。


3
投票

当你调用exec php时不会创建一个线程,它会创建一个新的子进程。创建一个新流程是一个很大的开销。

但是,当您使用ssh连接时,您只是传递一个命令来执行。您不是该程序的所有者,因此它以您连接的用户身份执行。对于exec来说,它是运行PHP的用户。


1
投票

这不是PHP错误,与Apache / Nginx或任何网络服务器无关。

我最近遇到了同样的问题并查看了PHP源代码以检查exec()实现。

本质上,PHP的exec()调用Libc的popen()函数。

这里的罪犯是C的popen(),这似乎很慢。快速谷歌搜索“c popen slow”将向您展示很多问题,例如你的。

我还发现有人在C中实现了一个名为popen_noshell()的函数来克服这个性能问题:

https://blog.famzah.net/2009/11/20/a-much-faster-popen-and-system-implementation-for-linux/

这是一个显示速度差异vs popen()和popen_noshell()的屏幕截图:

Speed difference

PHP exec()使用常规的popen() - 上面屏幕截图右侧的那个。执行C的popen()时系统使用的CPU非常高,如您所见。

我看到这个问题的2个解决方案:

  1. 创建一个实现popen_noshell的PHP扩展
  2. 请求PHP团队创建一组新函数popen_noshell(),exec_noshell()等...这不太可能发生我猜...

附加说明:

在搜索时,我发现了与C的名字相同的PHP函数:popen()

有趣的是因为可以异步执行外部命令:pclose(popen('your command','r'));

这基本上与exec('你的命令&')具有相同的效果;


0
投票

我遇到过这个问题,一个图形处理命令,通过命令行运行大约需要.025秒,在PHP中通过exec()调用大约需要0.3秒。经过大量研究,似乎大多数人认为这是apache或PHP的问题。然后我尝试通过CGI脚本运行命令,完全绕过PHP,我得到了相同的结果。

因此问题似乎必须是apache,所以我安装了lighttpd,并得到了相同的结果!

经过一番思考和实验,我意识到这一定是处理器优先级的问题。因此,如果您希望命令以与命令行类似的速度运行,则必须按如下方式执行。

exec('echo "password" | sudo -S nice -n -20 command')

请注意:我知道会有各种各样的安全异议。我只想简单地关注答案,你要做的就是在你的命令之前加上好的。

© www.soinside.com 2019 - 2024. All rights reserved.