我有一个XAMPP安装,几乎是默认配置.
一般来说,性能不是很大的问题,因为我主要使用PHP来运行网页和小型Web应用程序.等待几秒钟的页面并不罕见.
但是,我最近从Project Euler处理了问题,并决定用PHP来完成它们.
尽我所能,我不能让我的代码在不到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; }
最终编辑
start time:44:25:000000 #10001: 104759 End time:44:26:000000
代码:
<?PHP echo "start time:" . date("i:s:u") . "\n"; function isPrime($number,&$primes) { if ($number === 1) return false; elseif ($number %2 === 0) return false; elseif ($number < 4) return true; elseif ($number < 9) return true; elseif ($number %3 === 0) return false; else $r = floor(sqrt($number)); $f = 5; while ($f <= $r) { if ($number % $f ===0) return false; if ($number % ($f+2) === 0) return false; $f = $f + 6; } return true; } $primes = array(); $nbPrimes = $i = 0; while ($nbPrimes < 10001) { $i++; if (isPrime($i,$primes) !== false) { $primes[] = $i; $nbPrimes++; } } echo "#$nbPrimes: " . end($primes) . "\n"; echo "End time:" . date("i:s:u") . "\n";
Bakudan给了我伪代码,我刚刚翻译并为上面的OP脚本写出来.
编辑2
我清理了一下代码,没有改进任何东西,可能会增强“可读性”.但是,我认为这是你用PHP获得的最好的,在没有apache的i7上产生5秒.
<?PHP echo "start time:" . date("i:s:u") . "\n"; function isPrime($number,&$primes) { foreach($primes as $prime) { if ($number % $prime === 0 && $prime > 1) return false; } } $primes = array(); $nbPrimes = $i = 1; while ($nbPrimes <= 10001) { if ($i % 2 !== 0 && isPrime($i,$primes) !== false) { $primes[] = $i; $nbPrimes++; } $i++; } echo "#$nbPrimes: " . end($primes) . "\n"; echo "End time:" . date("i:s:u") . "\n";
编辑
通过将$prime === 1移动到同一if语句中的$number%$prime检查之后,敲掉另一秒.
start time:29:40:000000 #10001: 104743 End time:29:45:000000
采用Hannes建议严格检查并传递数组作为参考,并添加我自己的一些调整(修改函数内的数组):
ini_set('max_execution_time',300); echo "start time:" . date("i:s:u") . "\n"; function isPrime($number,&$prevPrimes) { foreach ($prevPrimes as $prime) { if ($number % $prime === 0 && $prime !== 1) { return false; } } // If we get to here,$number is prime $prevPrimes[] = $number; return $number; } $primes = array(); $i = 0; $nbPrimes = 0; while ($nbPrimes < 10001) { $i++; if ($i % 2 !== 0) { $result = isPrime($i,$primes); if ($result !== 0) { $nbPrimes++; } } } echo "#$nbPrimes: $result\n"; echo "End time:" . date("i:s:u") . "\n";
最终成为:
start time:52:08:000000 #10001: 104743 End time:52:15:000000
你的代码VS:
start time:50:44:000000 #10001: 104743 End time:51:17:000000