Mam kilka tysięcy rekordów (przechowywanych w tabeli w tabeli MYSQL), które muszę "przetworzyć w partiach". Wszystkie rekordy zawierają duży JSON. W niektórych przypadkach JSON wynosi ponad 1 MB (tak, mój DB ma znacznie ponad 1 GB).Uruchamianie intensywnego procesu wsadowego w PHP i unikanie wyczerpywania pamięci
Mam funkcję przechwytującą rekord, dekoduje JSON, zmienia niektóre dane, ponownie koduje tablicę PHP z powrotem do JSON i zapisuje ją z powrotem do bazy danych. Dość proste. FWIW, jest to w kontekście aplikacji CakePHP.
Biorąc pod tablicą identyfikatorów, ja próbuje zrobić coś takiego (bardzo prostego kodu mock):
foreach ($ids as $id) {
$this->Model->id = $id;
$data = $this->Model->read();
$newData = processData($data);
$this->Model->save($newData);
}
Problem jest to, że bardzo szybko, PHP zabraknie pamięci. Kiedy uruchamiasz foreach w ten sposób, to prawie tak, jakby PHP przenosiło się z jednego rekordu do drugiego, bez zwalniania pamięci wymaganej dla poprzednich operacji.
Czy istnieje jeszcze sposób uruchomienia pętli w taki sposób, aby pamięć została zwolniona przed przejściem do następnej iteracji pętli, tak aby faktycznie przetworzyć ogromną ilość danych?
Edytuj: Dodawanie więcej kodu. Ta funkcja pobiera mój JSON, konwertuje go do tablicy PHP, wykonuje pewne manipulacje (mianowicie rekonfigurację danych w oparciu o to, co jest obecne w innej tablicy) i zastępowanie wartości w oryginalnej tablicy. JSON ma wiele warstw głębokości, stąd niezwykle długie pętle 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;
}
Model-> read() zasadniczo po prostu mówi Cakeowi, aby wyciągnął rekord z db, i zwraca go w tablicy. Jest mnóstwo rzeczy, które dzieją się za kulisami, ktoś bardziej kompetentny musiałby to wyjaśnić.
Można spać na końcu każdej pętli, a jeśli używasz PHP 5.3 lub nowszej można (próbować) nazywamy śmieciarza. –
W czym pomoże sen? –
@therefromhere dać gc więcej czasu na kick lub zakończyć to, co robi. –