使用嵌套的for循环分解占用内存的PHP脚本


Break up memory hogging PHP script with nested for loops

我试图用这个脚本建立一个零件号表。我的内存快用完了。我已经注释掉了我甚至无法到达的循环:

 foreach ($mat_codes as $mat_code) {
     for ($n = 0; $n < count($shape_codes); $n++){
        for ($d1 = 0; $d1 <= 12; $d1++){
          for ($d1_dec = 1; $d1_dec <= 16; $d1_dec++){
            for ($d2 = 0; $d2 <= 12; $d2++){
              //for ($d2_dec = 1; $d2_dec <= 16; $d2_dec++){
                $build_part = (object) NULL;
                $build_part = $mat_code->part_code;
                $build_part .= $shape_codes[$n]->part_code;
                $build_part .= '.';
                if ($d1 != 0) {
                  $build_part .=  $d1 . '-';
                }
                $build_part .= $d1_dec;
                $build_part .= '.';
                //  if ($d2 != 0) {
                //    $build_part .=  $d2 . '-';
                //  }
                // $build_part .= $d2_dec;
                // $build_part .= '.';
                // * save $build_part to MYSQL * //
             //}
           }
        }
      }
    }
  }

不出所料,返回

PHP致命错误:允许的内存大小为134217728字节已耗尽(尝试分配71字节)

记录$mat_codes约有16个值,$shape_codes约有16个值。根据我的计算,我试图在这个例子中创建692,224个零件号。我想我还会增加更多,达到3400万。恕我直言,试图通过分配更多内存来完成这个任务是愚蠢的。我的问题——当然是——我如何把这个脚本分成更小的部分?

编辑:

我有个变通办法。很抱歉,这超出了我在原问题中定义的范围。我没有提到这只是一个潜在零件编号的表格。特别是,所有潜在的零件编号允许的逻辑零件编号系统。而不是有一个部件编号的主列表在准备等待使用,我想我可能会更好地验证新的部件输入对部件编号逻辑,像could_this_be_a_part_number($input)的功能。它可以根据零件编号逻辑测试输入的字符串,而不是需要检查的某个主表。

编辑x2:我很抱歉这是最糟糕的。我将unset($build_part)移到最内层的for循环中。问题是我试图在Drupal中的开发功能打印出每个$build_part之前,它被取消设置- dpm($build_part)。脚本运行良好,它试图建立一个网页,许多零件编号打印到它是什么打破了脚本。

首先:$build_part似乎不应该是一个对象,因为你把它当作一个字符串,所以不要那样初始化它。

$build_part = NULL;就足够了。

其次:我们不知道你希望你的数据如何保存在你的数据库中,但你可以(正如我最初的答案所建议的那样)建立一个查询,将其发送到数据库,然后继续。

现在让我们看看你的代码:

$i = 0;
foreach ($mat_codes as $mat_code) {
     for ($n = 0; $n < count($shape_codes); $n++){
        for ($d1 = 0; $d1 <= 12; $d1++){
          for ($d1_dec = 1; $d1_dec <= 16; $d1_dec++){
            for ($d2 = 0; $d2 <= 12; $d2++){
              for ($d2_dec = 1; $d2_dec <= 16; $d2_dec++){
                $i++;
                $build_part = (object) NULL;
                $build_part = $mat_code->part_code.".";
                $build_part .= $shape_codes[$n]->part_code;
                $build_part .= '.';
                if ($d1 != 0) {
                  $build_part .=  $d1 . '-';
                }
                $build_part .= $d1_dec;
                $build_part .= '.';
                 if ($d2 != 0) {
                   $build_part .=  $d2 . '-';
                 }
                $build_part .= $d2_dec;
                // echo "$i $build_part <br>";
                // * save $build_part to MYSQL * //
             }
             // This is first triggered when the count reaches 16 items
             echo "--- lvl 5<br>";
           }
           // 208 items
           echo "--- lvl 4<br>";
        }
        // 3328 items
        echo "--- lvl 3<br>";
      }
      echo "--- lvl 2<br>";
    }
    echo "--- lvl 1<br>";
}

我已经确定(你可以在其他地方做) 3级符号作为你可以向数据库发送一些预构建的MySQL查询的点。比如:

$mysqli->query("INSERT INTO parts ( part_id ) VALUES $very_long_string;");

也看看这个MySQL命令:INSERT DELAYED,我认为它可能(sic!)在你的情况下非常有用。

$very_long_string将构建在最内部的循环中,如:

$very_long_string .= "('$build_part'),";

和在最后(在我们创建和发送最后的查询之前),我们将删除最后一个逗号:

$very_long_string = rtrim($very_long_string, ",");

然后将3000+项长的查询发送到数据库中。然后取消设置($very_long_string)并重新开始。

所以我猜最终代码应该是这样的:

foreach ($mat_codes as $mat_code) {
for ($n = 0; $n < count($shape_codes); $n++){
    for ($d1 = 0; $d1 <= 12; $d1++){
        $very_long_string = null;
        for ($d1_dec = 1; $d1_dec <= 16; $d1_dec++){
            for ($d2 = 0; $d2 <= 12; $d2++){
                for ($d2_dec = 1; $d2_dec <= 16; $d2_dec++){
                $build_part = NULL;
                $build_part = $mat_code->part_code.".";
                $build_part .= $shape_codes[$n]->part_code;
                $build_part .= '.';
                if ($d1 != 0) {
                    $build_part .=  $d1 . '-';
                }
                $build_part .= $d1_dec;
                $build_part .= '.';
                if ($d2 != 0) {
                    $build_part .=  $d2 . '-';
                }
                $build_part .= $d2_dec;
                $very_long_string .= "('$build_part'),";
                }
            }
        }
        $very_long_string = rtrim($very_long_string, ",");
        $mysqli->query("INSERT INTO parts (part_id) VALUES $very_long_string;");
        unset($very_long_string);
    }
}
}

编辑后阅读你的编辑:我当然是处理的事实,你想填充数据库:D ..如果您需要一个验证函数,那就完全是另一回事了。