我有一个占用太多内存的cron作业(我后来发现它在我的服务器上达到了php超时)。我决定尝试通过重构代码来加载少量要操作的数据来修复它。假设Record是负责与数据库表'Record'连接的类,原始代码看起来类似于:
$allRecords = Record::getAll(); // $records contains Record instances from every record in the db, > 100k array elements
do{
$records = array_splice($allRecords, 500);
foreach($records as $record){
$record->doStuff(); // modify some data and save it back to the database
}
}while(!empty($allRecords))
现在代码看起来像这样:
$ids = Record::getAllIDs(); // $ids is an array of ints which are the id numbers for every record in the database
do{
$records = [];
foreach($ids as $key => $id){
$records[] = new Record($id); // add single Record instance to working pool
unset($id[$key]); // remove id so we don't do same thing twice
if(sizeof($records)===500) // only want 500 at a time to save on memory
break;
}
foreach($records as $record){
$record->doStuff(); // same as before
}
}while(!empty($ids))
显然,这会占用更少的系统内存,因为我首先想要做的就是这样做。令我困惑的是,这最终会占用相当少的时间。我经常看到这个cron需要一个多小时才能完成,现在需要15到20分钟才能运行相同数量的记录。任何人都有任何想法,为什么会出现这种情况?最后,我仍然从数据库中加载相同数量的记录,我认为将其分解会使其变慢,而不是更快。
答案 0 :(得分:1)
我的猜测是在磁盘上进行大量交换。
话虽如此,我认为你在循环中没有实际的好处 如果你删除它们,它应该表现得更好。
# as per your example try to run it like this
$ids = Record::getAllIDs(); // $ids is an array of ints which are the id numbers for every record in the database
foreach($ids as $key => $id){
new Record($id)->doStuff(); // add single Record instance to working pool
}