gpt4 book ai didi

php - Foreach() 和 each() 内存不足,分块不起作用

转载 作者:行者123 更新时间:2023-12-03 20:31:28 28 4
gpt4 key购买 nike

我正在编写一个 artisan 控制台命令,该命令循环遍历表中的所有记录并在该表上重新生成一个字段。

该字段是一个 hash 并且生成为特定字符串的 md5()

最初我的代码如下所示:

// Get all recipes
$recipes = Recipe::all();

$hashProgress = $this->output->createProgressBar(count($recipes));

// Loop over each recipe and generate a new hash for it
foreach ($recipes as $recipe)
{
$hashString = '';

$hashString .= $recipe->field1;
$hashString .= $recipe->field2;
$hashString .= $recipe->field3;
$hashString .= $recipe->field4;
$hashString .= $recipe->field5;
$hashString .= $recipe->field6;
$hashString .= $recipe->field7;

$extras1Total = $recipe->extras1->sum('amount');
$hashString .= $recipe->extras1->reduce(function ($str, $item) use ($extras1Total) {
return $str . $item->name . ($extras1Total == 0 ? $item->amount : ($item->amount / $extras1Total * 100));
}, '');

$extras2Total = $recipe->extras2->sum('amount');
$hashString .= $recipe->extras2->reduce(function ($str, $item) use ($extras2Total) {
return $str . $item->name . ($extras2Total == 0 ? $item->amount : ($item->amount / $extras2Total * 100));
}, '');

$extras3Total = $recipe->extras3->sum('amount');
$hashString .= $recipe->extras3->reduce(function ($str, $item) use ($extras3Total) {
return $str . $item->name . ($extras3Total == 0 ? $item->amount : ($item->amount / $extras3Total * 100));
}, '');

$extras4Total = $recipe->extras4->sum('amount');
$hashString .= $recipe->extras4->reduce(function ($str, $item) use ($extras4Total) {
return $str . $item->name . ($extras4Total == 0 ? $item->amount : ($item->amount / $extras4Total * 100));
}, '');

$recipe->update([
'hash' => md5($hashString),
]);

$hashProgress->advance();
}

$hashProgress->finish();
$this->info(' Recipe hashes regenerated.');

在达到 28,000 条记录中的大约 10,000 条后,它会因内存耗尽错误而死:

PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 4096 bytes)

我认为 chunk 这可能会有所帮助:

// Get all recipes
$recipes = Recipe::all();

$hashProgress = $this->output->createProgressBar(count($recipes));

// Loop over each recipe and generate a new hash for it
foreach ($recipes->chunk(1000) as $chunk)
{
foreach ($chunk as $recipe)
{
$hashString = '';

$hashString .= $recipe->field1;
$hashString .= $recipe->field2;
$hashString .= $recipe->field3;
$hashString .= $recipe->field4;
$hashString .= $recipe->field5;
$hashString .= $recipe->field6;
$hashString .= $recipe->field7;

$extras1Total = $recipe->extras1->sum('amount');
$hashString .= $recipe->extras1->reduce(function ($str, $item) use ($extras1Total) {
return $str . $item->name . ($extras1Total == 0 ? $item->amount : ($item->amount / $extras1Total * 100));
}, '');

$extras2Total = $recipe->extras2->sum('amount');
$hashString .= $recipe->extras2->reduce(function ($str, $item) use ($extras2Total) {
return $str . $item->name . ($extras2Total == 0 ? $item->amount : ($item->amount / $extras2Total * 100));
}, '');

$extras3Total = $recipe->extras3->sum('amount');
$hashString .= $recipe->extras3->reduce(function ($str, $item) use ($extras3Total) {
return $str . $item->name . ($extras3Total == 0 ? $item->amount : ($item->amount / $extras3Total * 100));
}, '');

$extras4Total = $recipe->extras4->sum('amount');
$hashString .= $recipe->extras4->reduce(function ($str, $item) use ($extras4Total) {
return $str . $item->name . ($extras4Total == 0 ? $item->amount : ($item->amount / $extras4Total * 100));
}, '');

$recipe->update([
'hash' => md5($hashString),
]);

$hashProgress->advance();
}
}

$hashProgress->finish();
$this->info(' Recipe hashes regenerated.');

但我仍然收到内存耗尽错误。

如何在不增加内存限制的情况下遍历所有这些记录并实现我的目标?

最佳答案

你“分 block ”的方式实际上比初始代码消耗更多的内存。

您所做的是一次获取所有记录,将它们存储在 $recipes 中,然后通过调用 chunk() on the resulted collection 将结果分 block .

相反,您需要调用具有相同名称的方法,chunk() ,在底层 Recipe 模型的查询构建器上,并逐 block 生成散列:

Recipe::chunk(1000, function ($recipies) {
// Hash generation logic here
});

这样,您就消除了一个巨大的 $recipes 变量,我确信这是这里的瓶颈。根据可用内存,您可能需要稍微调整 block 大小以避免内存耗尽。

另外,我会尝试在生成哈希时使用更少的变量,而不是留下 $extras1Totalextras2Total、... 变量的痕迹。所有这些都可以替换为将一遍又一遍地重写的 $total。这是微优化。

附注如果数据库写入压力很大(总共 28k 很少见),您可能需要考虑一次(或几次)进行最终更新,而不是每条记录都进行。

关于php - Foreach() 和 each() 内存不足,分块不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47296935/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com