为了账号安全,请及时绑定邮箱和手机立即绑定

如何提高 PHP 中 for 循环的速度?

如何提高 PHP 中 for 循环的速度?

PHP
子衿沉夜 2023-07-07 10:31:09
我有一个包含不同行的 CSV 文件:;0;1;0;4;5;M;468468;A1101;00900;1; 0;4;5;M;468468;A1108;0090例如,在照片文件夹中,第一个视图的命名格式必须为“A1101_0090-1.JPG”。我写了一段代码,它可以让你做两件事:csv 文件和照片文件夹中存在的图像的名称以及视图数照片文件夹中但不在 csv 文件中或被错误重命名的图像的名称。我的脚本可以工作,但是当我放置一个包含超过 5000 张照片的大照片文件夹时,处理时间非常长......我该如何改进我的代码?<?phpecho '<pre>';$dataImage = [];$dataImageTmp = [];$path = $_POST['path'];$photos = scandir($path);$photos = array_map('strtoupper', $photos);if (($handle = fopen("../RC_PRODUCT_HUB.csv", "r")) !== FALSE) {    $firstLine = true;    while (($data = fgetcsv($handle, 9000000, ";")) !== FALSE){        if (!$firstLine){            if ($data[0] != null) {                $countImage = count(glob($path . $data[6] . '_' . $data[7] . '*.*'));                for ($i = 0; $i <= $countImage; ++$i) {                    if ((file_exists($fileName = $path.$data[6].'_'.$data[7].'-'.$i.'.JPG'))){                        if (!in_array($fileName, $dataImage)){                            $dataImage[$data[6] . '_' . $data[7]]['file'][$i] = $fileName;                            $fileName = str_replace($path, '', $fileName);                            if (!in_array($fileName, $dataImageTmp)){                                $dataImageTmp[] = $fileName;                            }                        }                        $dataImage[$data[6] . '_' . $data[7]]['TOTAL'] = $countImage;                    }                }            }        }        $firstLine = false;    }     //FIRST PART    echo count($dataImage)." refs founds.<br>";    print_r($dataImage).'<br>';    //SECOND PART    $dataImageTmp = array_map('strtoupper', $dataImageTmp);     $resultat = array_diff($photos, $dataImageTmp);    $element = '.';    unset($resultat[array_search($element, $resultat)]);    $element2 = '..';    unset($resultat[array_search($element2, $resultat)]);    echo count($resultat)." photos found.<br>";    foreach ($resultat as $result) {        echo ($result) . '<br>';    }}?>
查看完整描述

2 回答

?
大话西游666

TA贡献1817条经验 获得超14个赞

别打电话glob()。只需使用一个循环来处理按数字顺序匹配模式的每个文件。当文件不存在时,您可以停止循环。


我假设您的文件名数字序列中没有间隙。


if (($handle = fopen("../RC_PRODUCT_HUB.csv", "r")) !== FALSE) {

    fgets($handle); // skip header line

    while (($data = fgetcsv($handle, 9000000, ";")) !== FALSE){

        if ($data[0] != null) {

            for ($i = 1; file_exists($fileName = $path.$data[6].'_'.$data[7].'-'.$i.'.JPG'); ++$i) {

                if (!in_array($fileName, $dataImage)){

                    $dataImage[$data[6] . '_' . $data[7]]['file'][$i] = $fileName;

                    $fileName = str_replace($path, '', $fileName);

                    if (!in_array($fileName, $dataImageTmp)){

                        $dataImageTmp[] = $fileName;

                    }

                }

                if (isset($dataImage[$data[6] . '_' . $data[7]]['TOTAL'])) {

                    $dataImage[$data[6] . '_' . $data[7]]['TOTAL']++;

                } else {

                    $dataImage[$data[6] . '_' . $data[7]]['TOTAL'] = 1;

                }

            }

        }

    }


查看完整回答
反对 回复 2023-07-07
?
Helenr

TA贡献1780条经验 获得超4个赞

需要注意的一些事项:

  • 为什么先count(glob(..))循环查找文件名( file_exists)?您只需glob($path . $data[6] . '_' . $data[7] . '*.JPG')获取文件名即可。您的解决方案首先创建一个所有文件名的数组,对其进行计数,然后丢弃它并为文件名创建一个全新的数组。

    您可以迭代 返回的数组glob,然后$i根据需要从文件名中提取。

  • 如果需要count(glob(..)),可以用 shell 命令替换它。我认为它们会更快,因为它们不需要 PHP 中的内存分配/释放。

    类似的东西shell_exec("ls '{$path}{$data[6]}_{$data[7]}*.*' | wc -l")。当然,这是针对基于 *nix 的系统和bash/sh. 您可以在其他操作系统(或 shell)中找到类似的东西。

  • 您可以以某种方式分割文件,并使用多个脚本来处理它们。该解决方案可能会有很大差异,具体取决于您想要的复杂程度。喜欢:

    • 预先拆分 csv 文件,然后对其运行脚本,然后合并结果。

    • 编写一个脚本来读取 csv 并运行多个进程,将 csv 文件的某些部分交给每个进程进行处理,然后合并结果。流程或类似的库在这里可能很有用。

    • 使用作业队列。脚本读取 csv 文件并为每一行(也许不是每一行,而是每 100 行)创建一个作业。作业由多个工作人员处理,结果保存在数据库或其他内容中以进行合并。有一些解决方案,但我只在 Laravel 或 Symfony 等有自己的作业队列的框架中使用它们。搜索一下php job queue,你会找到一些解决方案。


查看完整回答
反对 回复 2023-07-07
  • 2 回答
  • 0 关注
  • 145 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信