Разбор координатных данных в php и избежание фатальной ошибки памяти - PullRequest
0 голосов
/ 13 марта 2019

У меня есть координаты для данного маркера в виде строки, которую мне нужно преобразовать в 2-мерный массив, первый индекс - это массив значений 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? Я довольно новичок в программировании на php и удивляюсь, если использование взрыва таким образом израсходует много памяти , Я хочу убедиться, что мой код работает как можно лучше, прежде чем потенциально увеличить объем памяти, что я не хочу делать для этого из большого набора данных.

1 Ответ

0 голосов
/ 13 марта 2019

Использовать упаковщик файлового потока

Преимущество заключается в том, что при использовании файловых потоков ваш объем памяти невелик. Компромисс может быть немного медленнее или занимать больше времени.

Лучше (очевидно), если ваши данные уже есть в файле, но вы можете использовать строку. В этом случае вам придется создать временный файл, который, вероятно, добавляет немного накладных расходов. php://temp будет хранить приблизительно 2М данных в памяти (если я правильно помню), как 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 отдельный символ из этого ресурса (как поток).

Приветствие.

...