【问题标题】:Running an intensive batch process in PHP, and avoiding memory exhaustion在 PHP 中运行密集的批处理,并避免内存耗尽
【发布时间】:2013-04-12 07:49:58
【问题描述】:

我有几千条记录(存储在 MYSQL 表的表中)需要“批处理”。所有记录都包含一个大型 JSON。在某些情况下,JSON 超过 1MB(是的,我的数据库远远超过 1GB)。

我有一个函数可以抓取记录、解码 JSON、更改一些数据、将 PHP 数组重新编码回 JSON,然后将其保存回数据库。很简单。 FWIW,这是在 CakePHP 应用程序的上下文中。

给定一个 ID 数组,我正在尝试做这样的事情(非常简单的模拟代码):

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;
}

Model->read() 本质上只是告诉 Cake 从数据库中提取一条记录,并将其返回到一个数组中。幕后发生了很多事情,需要更有知识的人来解释一下。

【问题讨论】:

  • 您可以在每个循环结束时休眠,如果您运行的是 PHP 5.3 或更高版本,您可以(尝试)调用垃圾收集器。
  • 睡眠有什么帮助?
  • @therefromhere 让 gc 有更多时间开始工作,或者完成它正在做的事情。
  • @NicholasPickering 我看不出尝试一次处理超过 1GB 的数据如何帮助我解决内存问题。也许我错过了什么?
  • @BenjaminAllison 好点。我很傻,继续。

标签: php json cakephp memory memory-management


【解决方案1】:

我要做的第一步是确保所有内容都通过引用传递。

例如,

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

function processData(&$d){}

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

【讨论】:

  • 如果不再需要数据,自己致电unset() 是否明智?
猜你喜欢
  • 2010-12-15
  • 2017-03-26
  • 2015-10-01
  • 2011-11-25
  • 2021-12-07
  • 1970-01-01
  • 1970-01-01
  • 2014-09-08
相关资源
最近更新 更多