提高本地服务器上的PHP性能

Syl*_*rag 9 php xampp performance

我有一个XAMPP安装,几乎是默认配置.

一般来说,性能并不是什么大问题,因为我主要使用PHP来运行网页和小型网络应用程序.等待几秒钟的页面并不罕见.

但是,我最近从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 />";
Run Code Online (Sandbox Code Playgroud)

在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;  
}   
Run Code Online (Sandbox Code Playgroud)

Bak*_*dan 5

“使用武力 ......”的数学!只是抛出一些毫无意义的代码。以下是可以提高性能的几点。

  • 为什么要使用数组来匹配数字呢?
  • 因此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,.....

    号码divisable由3 - 3,6,9,12 - >我们已经有6和12,所以3,9,15,21 - > 3(2K-1)= 3(2x1-1)= 3,9,。 ..

这是来自项目euler hk管理员的一些伪代码

isPrime ( number )
{
    if ( number == 1 )      return false
    elseif ( number < 4 )       return true
    elseif ( number % 2 == 0 )  return false
    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
}
Run Code Online (Sandbox Code Playgroud)

聚苯乙烯

关于执行速度的差异-PHP是解释语言,要在浏览器中查看结果,您需要运行3个程序-浏览器,服务器,php解释器。您发出一个http请求,服务器调用php(可能还有很多其他东西,例如,日志记录), php读取并执行脚本。比C#中的步骤要多得多。

在C#中,将执行编译后的代码。


Jim*_* W. 3

最终编辑

以下是 Bakudan 逻辑中的 PHP 代码,它返回以下结果:

start time:44:25:000000
#10001: 104759
End time:44:26:000000
Run Code Online (Sandbox Code Playgroud)

代码:

<?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";
Run Code Online (Sandbox Code Playgroud)

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";
Run Code Online (Sandbox Code Playgroud)

编辑

通过将同一个语句中的$prime === 1to 移到检查之后,又缩短了一秒钟。$number % $primeif

start time:29:40:000000
#10001: 104743
End time:29:45:000000
Run Code Online (Sandbox Code Playgroud)

采用 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";
Run Code Online (Sandbox Code Playgroud)

最终结果是:

start time:52:08:000000
#10001: 104743
End time:52:15:000000
Run Code Online (Sandbox Code Playgroud)

VS你的代码:

start time:50:44:000000
#10001: 104743
End time:51:17:000000
Run Code Online (Sandbox Code Playgroud)

这是一个很好的改进,但没有什么能像 C# 那样,只是展示了编译语言的强大功能:)