2013-04-19 4 views
5

У меня есть несколько тысяч записей (хранящихся в таблице в таблице MYSQL), которые мне нужны для «пакетного процесса». Все записи содержат большой JSON. В некоторых случаях JSON составляет более 1 МБ (да, моя БД намного превышает 1 ГБ).Выполнение интенсивного пакетного процесса в PHP и предотвращение исчерпания памяти

У меня есть функция, которая захватывает запись, декодирует JSON, изменяет некоторые данные, перекодирует массив PHP обратно в JSON и сохраняет его обратно в db. Довольно просто. FWIW, это в контексте приложения CakePHP.

Учитывая массив идентификаторов, я пытаюсь сделать что-то вроде этого (очень простой макет кода):

foreach ($ids as $id) { 
    $this->Model->id = $id; 
    $data = $this->Model->read(); 
    $newData = processData($data); 
    $this->Model->save($newData); 
} 

Вопрос заключается в том, что очень быстро, PHP работает из памяти. При запуске foreach, как это, это почти так, как если бы PHP перемещался из одной записи в другую, не освобождая память, необходимую для предыдущих операций.

Нужно ли все-таки запустить цикл таким образом, чтобы память освобождалась, прежде чем перейти к следующей итерации цикла, чтобы я мог обработать огромное количество данных?

Редактировать: добавление большего количества кода. Эта функция принимает мой JSON, преобразует его в массив PHP, выполняет некоторые манипуляции (а именно, реконфигурирует данные на основе того, что присутствует в другом массиве) и заменяет значения в исходном массиве. JSON - это много слоев, поэтому очень длинные петли foreach.

function processData($theData) { 
    $toConvert = json_decode($theData['Program']['data'], $assoc = true); 
    foreach($toConvert['cycles'] as $cycle => $val) { 
     foreach($toConvert['cycles'][$cycle]['days'] as $day => $val) { 
      foreach($toConvert['cycles'][$cycle]['days'][$day]['sections'] as $section => $val) { 
       foreach($toConvert['cycles'][$cycle]['days'][$day]['sections'] as $section => $val) { 
        foreach($toConvert['cycles'][$cycle]['days'][$day]['sections'][$section]['exercises'] as $exercise => $val) { 
         if (isset($toConvert['cycles'][$cycle]['days'][$day]['sections'][$section]['exercises'][$exercise]['selectedFolder'])) { 
          $folderName = $toConvert['cycles'][$cycle]['days'][$day]['sections'][$section]['exercises'][$exercise]['selectedFolder']['folderName']; 
          if (isset($newFolderList['Folders'][$folderName])) { 
           $toConvert['cycles'][$cycle]['days'][$day]['sections'][$section]['exercises'][$exercise]['selectedFolder'] = $newFolderList['Folders'][$folderName]['id']; 
          } 
         } 
         if (isset($toConvert['cycles'][$cycle]['days'][$day]['sections'][$section]['exercises'][$exercise]['selectedFile'])) { 
          $fileName = basename($toConvert['cycles'][$cycle]['days'][$day]['sections'][$section]['exercises'][$exercise]['selectedFile']['fileURL']); 
          if (isset($newFolderList['Exercises'][$fileName])) { 
           $toConvert['cycles'][$cycle]['days'][$day]['sections'][$section]['exercises'][$exercise]['selectedFile'] = $newFolderList['Exercises'][$fileName]['id']; 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
    return $toConvert; 
} 

Модель-> прочитать() в основном только говорит торт, чтобы вытащить запись из БД и возвращает его в массив. Есть много вещей, которые происходят за кулисами, кто-то более осведомленный должен был бы объяснить это.

+0

Вы могли бы спать в конце каждого цикла, и если вы используете PHP 5.3 или выше, вы можете (попытаться) вызвать сборщик мусора. –

+0

Как спать поможет? –

+0

@therefromhere дать gc больше времени, чтобы ударить или закончить то, что он делает. –

ответ

2

Первый шаг, который я сделал бы, это убедиться, что все передано по ссылке.

Например,

foreach ($ids as $id) { 
processData($data); 
} 

function processData(&$d){} 

http://php.net/manual/en/language.references.pass.php

+0

Отличная идея! Я принимаю это в JS ... –

+1

Было бы разумно называть 'unset()' самостоятельно, если данные больше не нужны? –