【问题标题】:Parsing Coordinate data in php and avoid fatal memory error在php中解析坐标数据并避免致命的内存错误
【发布时间】:2019-08-04 12:08:18
【问题描述】:

我将给定标记的坐标作为字符串,我需要将其转换为二维数组,第一个索引是 x 值数组,第二个索引是 y。

对于每个标记,坐标字符串如下所示:

$strCoordinatesMarker1 = "0,0,12:0,43,4";

上述示例的输出仅针对单个标记将是

$coordinatesMarker 1 = Array
(
    [0] => Array
        (
            [0] => 0
            [1] => 0
            [2] => 12
        )
(
    [1] => Array
        (
            [0] => 0
            [1] => 43
            [2] => 4
        )
)

文件输出一个包含所有标记和每个坐标数据的数组

到目前为止,我的代码在此方面运行良好

// Looping through the query of markers from the DB 
// $strCoordinates is returned for each:

while ($stmt->fetch()) {
    $xyArray = explode(':', $strCoordinates);
    $coordinates = array(explode(',', $xyArray[0]), explode(',', $xyArray[1]));

    $completeCoordinates[] = array('coordinates' => $coordinates);
}

这适用于小型数据集,我最近得到了一个有 300 个标记的数据集,每个标记有超过 3500 个坐标。

在这个数据集上尝试我的代码我得到了错误:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted
(tried to allocate 72 bytes)

所以我的问题是:会有更有效的方法在 php 中进行这种解析吗?记忆。我想确保我的代码尽可能地发挥作用,然后才可能增加内存,而我真的不想为这个大型数据集做这件事。

【问题讨论】:

  • 要问的更好的问题是:您真的需要将所有 3500 个坐标同时保存在内存中吗?如果没有,请丢弃您不再需要的数据

标签: php string memory-leaks coordinates explode


【解决方案1】:

使用文件流包装器

这里的好处是在使用文件流时你的内存占用很小。权衡是它可能会慢一些或总体上需要更长的时间。

如果您的数据已经在文件中,则更好(显然),但您可以使用字符串。在这种情况下,您必须创建一个临时文件,这可能会增加一些开销。 php://temp 将在内存中保留 apx 2M 的数据(如果我没记错的话),就像 php://memory 一样,但与流资源不同的是,它会开始将大于该数据的数据卸载到临时文件中。

//If you have a string you can use a temp file
//I mainly did this as it's easier for me to test it
$f = fopen('php://temp', 'w+'); //open in write + read
fwrite($f, "0,0,12:0,43,4");  //write the string to tmp 
rewind($f); //rewind the file to the start, reset the file pointer

//if you have a file you can do this instead of the above 
//$f = fopen('yourfile.txt', 'r');
$result = [];
$buffer = '';
$sub = [];

while(!feof($f)){   
    $c = fgetc($f);
    if(':' == $c || false === $c){
        if(!empty($buffer)){
            $sub[] = $buffer;
            $buffer = '';
        }
        if(!empty($sub)){
            $result[] = $sub;
            $sub = [];
        }
    }elseif(',' == $c){
            $sub[] = $buffer;
            $buffer = '';
    }else{
            $buffer .= $c;
    } 
}

print_r($result);

输出

Array(
    [0] => Array(
            [0] => 0
            [1] => 0
            [2] => 12
        )   
    [1] => Array(
            [0] => 0
            [1] => 43
            [2] => 4
        )
)

我应该补充一点,这应该可以处理可变长度的部分,只要你只有0-9:, 就可以了。如果你有其他东西,那将在输出数组in the }else{ 中结束。也就是说,很容易添加另一个条件来处理它。例如,我测试了这个字符串0,0,12:0,43,4::0,2,6,454654,3,它给了我以下输出:

Array(
    [0] => Array(
            [0] => 0
            [1] => 0
            [2] => 12
        )  
    [1] => Array(
            [0] => 0
            [1] => 43
            [2] => 4
        )    
    [2] => Array(
            [0] => 0
            [1] => 2
            [2] => 6
            [3] => 454654
            [4] => 3
        )    
)

不幸的是,出于安全原因,我所知道的在线沙盒都不允许您使用文件功能。不过我确实在本地测试过。

无论如何,这不是我可以真正进行基准测试的东西,这些只是我对其他解析数据的方法的一些快速想法。

最后一个想法

看起来您将其存储在数据库中。如果是这种情况,您必须从某个地方获取它以将其放入数据库中:

我最近得到了一个 300 标记的..

这意味着您最近获得了一些“新”数据。因此,您可以将其解析卸载到您将其添加到数据库的位置。然后以更好的格式存储它,这样您以后就不必解析它,例如 JSON 或序列化数组等。然后,当您在这里执行所有其他操作时,您可以通过预加载已经格式化的格式来避免这种情况.另外我不知道您的来源是什么,它可能是 URL(也可以用作文件),也可能是您下载的东西等。

这实际上是一种非常强大的数据解析方式,我已经完成了 Gb 范围内的事情。处理需要更长的时间,但唯一的内存使用是保持资源打开并从该资源中读取 1 个单个字符(作为流)。

干杯。

【讨论】:

  • 例如使用了三个元素,长度可以相差很大,我的代码中断是在3500时
  • 你确实把这个So my question is: Would there be a more efficient way to do this parsing in php? 提供了一个更好的例子来说明这些差异。例如,可以使用preg_match_all
猜你喜欢
  • 2019-01-29
  • 2017-07-31
  • 2014-12-21
  • 2011-06-12
  • 1970-01-01
  • 1970-01-01
  • 2014-06-01
  • 2015-07-02
  • 1970-01-01
相关资源
最近更新 更多