提高本地服务器上 php 的性能
我安装了 XAMPP,几乎使用默认配置。
一般来说,性能并不是什么大问题,因为我主要使用 PHP 来运行网页和小型 Web 应用程序。等待几秒钟的页面并不罕见。
然而,我最近处理了 Project Euler 中的问题,并决定用 PHP 来解决。
尽我所能,我无法让我的代码在不到 1 分 1 秒的时间内运行(从近 3 分钟优化而来),我感到非常尴尬,特别是考虑到 Pjt Euler 上的大多数海报报告的时间为 1-3 秒。 (#7,找到第 10001 个素数)
我将代码移植到 C#,眨眼间就完成了相同的任务。 0.4秒。相同的算法,代码中唯一显着的区别是我使用 C# 中的 List 来替换 PHP 中使用的数组。
虽然我确实期望 C# 的性能优于 php,但这种差异让我怀疑存在严重的配置问题,但我不知道该去哪里查找。
造成这种糟糕表现的原因可能是什么?
编辑:这是代码:
在 PHP 中:
/*
* Project Euler #7:
* By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
* What is the 10001st prime number?
*/
ini_set('max_execution_time', 300);
echo "start time:" . date("i:s:u") . "<br />";
function isPrime($number, $prevPrimes)
{
foreach ($prevPrimes as $key =>$prime)
{
if ($prime == 1)
{
continue;
}
elseif ($number % $prime == 0)
{
return 0;
}
}
// If we get to here, $number is prime
return $number;
}
$primes = array();
$i = 0;
$nbPrimes = 0;
while ($nbPrimes <10001)
{
$i++;
if ($i % 2 != 0)
{
$result = isPrime($i, $primes);
if ($result != 0)
{
$primes[] = $i;
$nbPrimes++;
}
}
}
echo "#$nbPrimes: $result<br>";
echo "End time:" . date("i:s:u") . "<br />";
在 C# 中:
public static void RunSnippet()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<int> primes = new List<int>();
int i = 0;
int nbPrimes = 0;
int result =0;
while (nbPrimes <10001)
{
i++;
if (i % 2 != 0)
{
result = isPrime(i, primes);
if (result != 0)
{
primes.Add(i);
nbPrimes++;
}
}
}
stopwatch.Stop();
Console.WriteLine("Time elapsed: {0}",
stopwatch.Elapsed);
Console.WriteLine ("#" + nbPrimes + ": " + result.ToString());
}
public static int isPrime(int number, List<int> prevPrimes)
{
foreach (int prime in prevPrimes)
{
if (prime == 1)
{
continue;
}
else if (number % prime == 0)
{
return 0;
}
}
// If we get to here, number is prime
return number;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
“使用数学的力......”!只是抛出一些毫无意义的代码。以下是可以提高性能的几点。
因此 foreach 函数无效 - 循环应在
floor(sqrt(number))
处结束
示例:sqrt(64) = 8 ->所有素数除法器都是从 1 到 8。其他的将是它们的乘积( 32 = 4 x 8 = 2x2x2x2x2 )
使用公式跳转到下一个可能的质数
数学:
可被 2 - 2、4、6、8、10、12 整除的数字 -> 2k+1 = 2x1+1 = 3, 5, .....
可被 3 - 3、6、9、12 整除的数字 ->我们已经有 6 和 12,所以 3, 9, 15, 21 -> 3(2k-1) = 3(2x1-1) = 3, 9, ...
这里有一些 来自 href="http://projecteuler.net/profile/hk.png" rel="nofollow">hk admin at project euler
PS
关于执行速度的差异 - PHP 是解释性语言,
要在浏览器中查看结果,您需要运行 3 个程序 - 浏览器、服务器、php 解释器。您发出一个 http 请求,服务器调用 php(可能还调用一些其他内容,例如日志记录),php 读取脚本并执行它。步骤比 C# 多得多。在 C# 中,执行编译后的代码。
"Use the force ..." of math! Just throwing some code pointless. Here are just a few points that can boost the performance.
the foreach function is thus ineffective - the cycle should end at
floor(sqrt(number))
example: sqrt(64) = 8 -> all prime dividers will be from 1 to 8. The others will be product of them( 32 = 4 x 8 = 2x2x2x2x2 )
use formulas to jump to the next possibly prime number
math:
numbers divisable by 2 - 2, 4, 6, 8, 10, 12 -> 2k+1 = 2x1+1 = 3, 5, .....
numbers divisable by 3 - 3, 6, 9, 12 -> we already have 6 and 12, so 3, 9, 15, 21 -> 3(2k-1) = 3(2x1-1) = 3, 9, ...
here is some pseudo code from hk admin at project euler
PS
About the difference in the speed of the execution - PHP is interpreted language,
to view the result in browser you have 3 programs running - browser, server, php interpreter. You make a http request, the server calls php (and probably a bunch of other stuff, logging for example),php reads the script and executes it. There are much more steps than in C#.In C# the compiled code is executed.
最终编辑
这是来自 Bakudan 逻辑的 PHP 代码,它返回以下结果:
代码:
Bakudan 给了我伪代码,我刚刚翻译并为 OP 编写了它上面的脚本。
编辑2
我稍微清理了代码,没有改进任何东西,可能会增强“可读性”。但是,是的,我认为这是使用 PHP 所能得到的最好的结果,在没有 apache 的 i7 上,它只需要 5 秒。
编辑
通过将
$prime === 1
移动到同一中的
语句。$number % $prime
检查之后,又敲了一秒>if采用 Hannes 建议的严格检查和传递数组作为参考,加上我自己的一些调整(修改函数内的数组):
最终结果是:
VS 你的代码:
这是一个很好的改进,但没有像 C# 那样的东西展示编译语言的力量:)
FINAL EDIT
Here is the PHP code from Bakudan's logic, which returns this result:
The Code:
Bakudan gave me the pseudo code, I Just translated and wrote it out for the OP's script above.
EDIT 2
I cleaned up the code a bit, didn't improve anything, may enhance "readability". But yea, I think this is the best you will get with PHP, which on an i7 without apache yields 5 seconds.
EDIT
Knocked another second off by moving the
$prime === 1
to be after the$number % $prime
check in the sameif
statement.Taking Hannes suggestion of strict checking and passing the array as reference plus adding a few tweaks of my own (modifying the array inside the function):
Which ended up being:
VS your code:
A good improvement there, but nothing like C#, just goes to show the power of a compiled language :)
启动 PHP 引擎会给网络服务器带来一些开销。 PHP 的加载方式(例如,在服务器启动时作为模块加载或为每个.php 请求按需加载)决定了涉及多少开销。然后在 Windows 上有两种可用的 PHP 变体:线程安全的和非线程安全的,后者据称更快。
如果是 XAMPP 配置问题,我认为您可以通过在网络服务器上运行测试 3 次并记下平均时间来隔离它。然后通过 PHP CLI 运行相同的脚本 3 次并记下平均值。如果差异很明显,那么您可能会责怪 XAMPP。您应该能够在 XAMPP 安装文件夹内的某个位置找到 PHP CLI 二进制文件。
在我的系统上,我得到以下结果:
没有太大区别 - 我宁愿优化代码。
编辑
同一台机器,除了执行时间之外,使用此修改后的代码将执行时间从约 30 秒缩短到约 5.85 秒。唯一值得一提的是,我使用了全局数组,而不是每次调用 isPrime 函数时都按值传递(准确地说是 104743 次)。通过引用传递数组也会导致类似的执行时间,相差 1 秒。比较运算符只缩短了一两秒,但幅度不大。
Firing the PHP engine creates a little overhead for the webserver. The way PHP is loaded (e.g. loaded as a module on server startup or loaded on demand for every .php request) determines how much overhead is involved. Then on windows there are two variants of PHP available: thread-safe and non thread-safe, the latter one is claimed to be faster.
If its a XAMPP configuration problem, I think you can isolate it by running the test 3 times on your webserver and note down the average time. Then run the same script via PHP CLI 3 times and note down the average. If the difference is noticeable then you might blame XAMPP. You should be able to locate the PHP CLI binary somewhere inside the XAMPP installation folder.
On my system I get these results:
Not much of a difference -- I would rather optimize the code.
EDIT
Same machine and everything but execution time brought down from ~30 seconds to ~5.85 seconds with this revised code. The only thing worth mentioning is that that I used a global array instead of passing it by value every time the isPrime function is called (104743 times to be precise). Passing the array by reference also results in similar execution time, give or take 1 second. The comparison operators shave off just a second or two but not much.