如何提高 PHP 中 for 循环的速度?
How to improve the speed of a for loop in PHP?
我有一个包含不同行的 CSV 文件:
;0;1;0;4;5;M;468468;A1101;0090
0;1;0;4;5;M;468468;A1108;0090
并且在照片文件夹中,例如第一个视图的命名格式必须为“A1101_0090-1.JPG”。
我写了一个代码,让你有两个东西:
- csv 文件和照片文件夹中的图片名称,以及浏览次数
- 照片文件夹中但不在 csv 文件中或重命名不正确的图像的名称。
我的脚本有效,但是当我放入一个包含 5000 多张照片的大照片文件夹时,处理时间很长...我该如何改进我的代码?
<?php
echo '<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>';
}
}
?>
一些注意事项:
为什么先count(glob(..))
然后再循环查找文件名(file_exists
)?您只需执行 glob($path . $data[6] . '_' . $data[7] . '*.JPG')
即可获取文件名。您的解决方案首先创建一个包含所有文件名的数组,对它进行计数,然后丢弃它并为文件名创建一个全新的数组。
您可以遍历 glob
返回的数组,然后根据需要从文件名中提取 $i
。
如果你需要那个count(glob(..))
,你可以用shell命令替换它。我认为它们会更快,因为它们不需要内存 allocation/deallocation in PHP.
类似于shell_exec("ls '{$path}{$data[6]}_{$data[7]}*.*' | wc -l")
。当然,这是针对基于 *nix 的系统和 bash/sh
。您可以为其他 OS(或 shell)找到类似的东西。
您可以以某种方式拆分文件,然后使用多个脚本来处理它们。根据您想要的复杂程度,此解决方案可能会有很大差异。喜欢:
- 预先拆分 csv 文件,然后 运行 在其上编写脚本,然后合并结果。
- 写一个脚本读取csv,运行多个进程,把csv文件的一部分给每个进程处理,然后合并结果。 Process 或类似的库在这里很有用。
- 使用作业队列。脚本读取 csv 文件并为每一行创建一个作业(可能不是每一行,但就像每 100 行)。作业由多个工作人员处理,结果保存在数据库或要合并的东西中。有一些解决方案,但我只在 Laravel 或 Symfony 等框架中使用它们,它们有自己的作业队列。搜索
php job queue
,您会找到一些解决方案。
不要打电话给 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;
}
}
}
}
}
我有一个包含不同行的 CSV 文件:
;0;1;0;4;5;M;468468;A1101;0090
0;1;0;4;5;M;468468;A1108;0090
并且在照片文件夹中,例如第一个视图的命名格式必须为“A1101_0090-1.JPG”。
我写了一个代码,让你有两个东西:
- csv 文件和照片文件夹中的图片名称,以及浏览次数
- 照片文件夹中但不在 csv 文件中或重命名不正确的图像的名称。
我的脚本有效,但是当我放入一个包含 5000 多张照片的大照片文件夹时,处理时间很长...我该如何改进我的代码?
<?php
echo '<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>';
}
}
?>
一些注意事项:
为什么先
count(glob(..))
然后再循环查找文件名(file_exists
)?您只需执行glob($path . $data[6] . '_' . $data[7] . '*.JPG')
即可获取文件名。您的解决方案首先创建一个包含所有文件名的数组,对它进行计数,然后丢弃它并为文件名创建一个全新的数组。您可以遍历
glob
返回的数组,然后根据需要从文件名中提取$i
。如果你需要那个
count(glob(..))
,你可以用shell命令替换它。我认为它们会更快,因为它们不需要内存 allocation/deallocation in PHP.类似于
shell_exec("ls '{$path}{$data[6]}_{$data[7]}*.*' | wc -l")
。当然,这是针对基于 *nix 的系统和bash/sh
。您可以为其他 OS(或 shell)找到类似的东西。您可以以某种方式拆分文件,然后使用多个脚本来处理它们。根据您想要的复杂程度,此解决方案可能会有很大差异。喜欢:
- 预先拆分 csv 文件,然后 运行 在其上编写脚本,然后合并结果。
- 写一个脚本读取csv,运行多个进程,把csv文件的一部分给每个进程处理,然后合并结果。 Process 或类似的库在这里很有用。
- 使用作业队列。脚本读取 csv 文件并为每一行创建一个作业(可能不是每一行,但就像每 100 行)。作业由多个工作人员处理,结果保存在数据库或要合并的东西中。有一些解决方案,但我只在 Laravel 或 Symfony 等框架中使用它们,它们有自己的作业队列。搜索
php job queue
,您会找到一些解决方案。
不要打电话给 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;
}
}
}
}
}