Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP代码达到执行时间限制_Php_Performance_Execution Time_Haversine - Fatal编程技术网

PHP代码达到执行时间限制

PHP代码达到执行时间限制,php,performance,execution-time,haversine,Php,Performance,Execution Time,Haversine,我需要遍历一个包含地图中的点的数组,并检查它们之间的距离。我需要计算每个节点200米和50米范围内的节点数。它适用于较小数量的值。但是,当我尝试在4000左右运行更多值以进行可伸缩性测试时,出现了一个错误,表示我已达到300秒的最大执行时间。如果可能的话,它需要能够在300秒内处理至少这么多 我读了很多书,发现有一种方法可以禁用/更改此限制,但我想知道是否有一种更简单的方法可以执行以下代码,从而减少运行时间 索引0包含每个节点的唯一ID,1包含每个节点的纬度,以及 索引2包含每个节点的经度 错误

我需要遍历一个包含地图中的点的数组,并检查它们之间的距离。我需要计算每个节点200米和50米范围内的节点数。它适用于较小数量的值。但是,当我尝试在4000左右运行更多值以进行可伸缩性测试时,出现了一个错误,表示我已达到300秒的最大执行时间。如果可能的话,它需要能够在300秒内处理至少这么多

我读了很多书,发现有一种方法可以禁用/更改此限制,但我想知道是否有一种更简单的方法可以执行以下代码,从而减少运行时间

索引0包含每个节点的唯一ID,1包含每个节点的纬度,以及 索引2包含每个节点的经度


错误发生在第一个循环内的第二个for循环。此循环用于将选定的贴图节点与其他节点进行比较。我也在使用哈弗森公式。

首先,你用的是大O符号:Odata^2,这将非常缓慢,实际上,有两种可能的解决方案。找到一个经过验证的算法,在更好的时间内解决相同的问题。或者,如果不能,开始将内容移出inner for循环,并以数学方式证明是否可以将内部for循环转换为大多数简单的计算,这通常是您可以做到的

经过一些改写,我看到了一些可能性: 如果$data不是一个具有更好访问时间的SPLFixedArray,那么就使用它。因为您多次访问该数据4000^2*2。 secound,写更干净的代码。尽管optizmier会尽其所能,但如果您不尝试缩小代码以使其更具可读性,那么它可能无法做到最好


并将中间结果移出循环,也就是数组的大小

当前,您正在对照所有其他点检查所有点,实际上,您只需要对照所有剩余点检查当前点。从A到B的距离与从B到A的距离相同,为什么要计算两次呢

我可能会创建一个相邻的数组来计算彼此之间的范围内有多少个节点,并在计算两个节点彼此之间的范围后,增加该数组中的条目对

在计算真正的距离之前,您可能会得到一个非常快速的距离近似值,该近似值可用于忽略尽可能多的节点,而实际距离永远不会非常快

一般来说,除了算法优化外,优化的基本规则包括:

不要做任何你不必做的处理:比如不把$distance乘以1000。只需将测试的值分别从20和50更改为0.02和0.05

不要过于频繁地调用任何函数:在任何处理开始之前,只需调用count$data一次

不要多次计算常量值:例如,PI/180

将所有可能的处理移到循环之外。即尽可能地预先计算

另一个让您的代码更容易阅读的要点:

对于$i=0$我试试这个:

$max = count($data);
$CONST_PI = PI() / 180;

for($i=0;$i<$max;$i++)
{
    $amount200a=0;
    $amount50a=0;

    $long_a = $data[$i][2] * $CONST_PI;
    $lat_a = $data[$i][1] * $CONST_PI;

    for($_i=0;$_i<=$max;$_i++) 
    //or use for($_i=($i+1);$_i<=$max;$_i++) if you did not need to calculate already calculated in other direction
    {
        $distance=0;
        if($data[$i][0]===$data[$_i][0]) continue;

        $lat_b = $data[$_i][1] * $CONST_PI;
        $long_b = $data[$_i][2] * $CONST_PI;
        $distance =
                acos(
                        sin($lat_a ) * sin($lat_b) +
                        cos($lat_a) * cos($lat_b) * cos($long_b - $long_a)
                ) * 6371;
        if ($distance<=0.2)
        {
            $amount200a++;
            if ($distance<=0.05)
            {
                $amount50a++;
            }
        }
    } // for %_i
    $amount200p=100*number_format($amount200a/$max,2,'.','');
    $amount50p=100*number_format($amount50a/$max,2,'.','');

    $dist.=$data[$i][0]."&&".$amount200a."&&".$amount200p."&&".$amount50a."&&".$amount50p."%%";
} // for $i

我认为阅读会更好,如果您更改for$\I的注释行,则速度会更快:

计算循环外的不变量:count$data、PI/100等。
$max = count($data);
$CONST_PI = PI() / 180;

for($i=0;$i<$max;$i++)
{
    $amount200a=0;
    $amount50a=0;

    $long_a = $data[$i][2] * $CONST_PI;
    $lat_a = $data[$i][1] * $CONST_PI;

    for($_i=0;$_i<=$max;$_i++) 
    //or use for($_i=($i+1);$_i<=$max;$_i++) if you did not need to calculate already calculated in other direction
    {
        $distance=0;
        if($data[$i][0]===$data[$_i][0]) continue;

        $lat_b = $data[$_i][1] * $CONST_PI;
        $long_b = $data[$_i][2] * $CONST_PI;
        $distance =
                acos(
                        sin($lat_a ) * sin($lat_b) +
                        cos($lat_a) * cos($lat_b) * cos($long_b - $long_a)
                ) * 6371;
        if ($distance<=0.2)
        {
            $amount200a++;
            if ($distance<=0.05)
            {
                $amount50a++;
            }
        }
    } // for %_i
    $amount200p=100*number_format($amount200a/$max,2,'.','');
    $amount50p=100*number_format($amount50a/$max,2,'.','');

    $dist.=$data[$i][0]."&&".$amount200a."&&".$amount200p."&&".$amount50a."&&".$amount50p."%%";
} // for $i