php 如何能让代码一个一个执行而不占用CPU和内存呢?

时间:2022-09-01 22:52:02
是这样的,我想遍历网站下的uploads文件夹下多个目录(按日期文件夹存放着图片)里面的图片,可能有5、6千张图片,遍历的时候一个一个的插入到我指定的mysql数据表中,我下面这样写会卡一会,有没有更好的办法或者写法呢?能让程序遍历100条后提示文字,即将继续。。。然后又接着遍历,能做到那样吗?

function traversing($path)
{
    $curr = glob($path.'/*');
    if($curr)
{
        foreach($curr as $f)
{
            if(is_dir($f))
{
                traversing($f);
            }
elseif(strtolower(substr($f, -4))=='.jpg')
{
$dosql->ExecNoneQuery("INSERT INTO `#@__uploads` (path) VALUES ('$f')");
            }
elseif(strtolower(substr($f, -4))=='.gif')
{
$dosql->ExecNoneQuery("INSERT INTO `#@__uploads` (path) VALUES ('$f')");
            }
elseif(strtolower(substr($f, -4))=='.png')
{
$dosql->ExecNoneQuery("INSERT INTO `#@__uploads` (path) VALUES ('$f')");
            }
elseif(strtolower(substr($f, -5))=='.jpeg')
{
$dosql->ExecNoneQuery("INSERT INTO `#@__uploads` (path) VALUES ('$f')");
            }
        }
    }
}

traversing('upload');

9 个解决方案

#1


才几千条,先扫描后入库,很快的

#2


换个写法,不用递归
function traversing($path) {
  $p = array($path); //待遍历的目录
  for($i=0; $i<count($p); $i++) {
    $p = array_merge($p, glob("{$p[$i]}/*", GLOB_ONLYDIR)); //将本级子目录加入待遍历的目录
    $a = preg_grep('/\.(jpeg|jpg|png|gif)/i', glob("{$p[$i]}/*")); //读取本级目录列表,并过滤出图片文件名
    $v = join("'),('", $a);
    $sql = "INSERT INTO `#@__uploads` (path) VALUES ('$v')"; //构造批量插入指令
    $dosql->ExecNoneQuery($sql);
  }
}

在递归写法中,每一层读取的目录列表($curr)所占的内存,要等到本层返回时才会被释放
这显然是很耗内存的
一条条的判断、插入,也不如批量插入来的快

#3


引用 2 楼 xuzuning 的回复:
换个写法,不用递归
function traversing($path) {
  $p = array($path); //待遍历的目录
  for($i=0; $i<count($p); $i++) {
    $p = array_merge($p, glob("{$p[$i]}/*", GLOB_ONLYDIR)); //将本级子目录加入待遍历的目录
    $a = preg_grep('/\.(jpeg|jpg|png|gif)/i', glob("{$p[$i]}/*")); //读取本级目录列表,并过滤出图片文件名
    $v = join("'),('", $a);
    $sql = "INSERT INTO `#@__uploads` (path) VALUES ('$v')"; //构造批量插入指令
    $dosql->ExecNoneQuery($sql);
  }
}

在递归写法中,每一层读取的目录列表($curr)所占的内存,要等到本层返回时才会被释放
这显然是很耗内存的
一条条的判断、插入,也不如批量插入来的快

目录文件少的可以,文件多的目录没有遍历进去,这是为什么呢?第一个文件夹的能入库,第二个文件夹的不能入库。
php 如何能让代码一个一个执行而不占用CPU和内存呢?
php 如何能让代码一个一个执行而不占用CPU和内存呢?
php 如何能让代码一个一个执行而不占用CPU和内存呢?


#4


文件太多了!
可用 array_chunk 将数组切成小段,分别处理

#5


引用 4 楼 xuzuning 的回复:
文件太多了!
可用 array_chunk 将数组切成小段,分别处理

array_chunk 不懂怎么切呢,可以让代码休息10秒后继续的办法吗?感觉那样没那么占内存。

#6


function traversing($path) {
  $p = array($path); //待遍历的目录
  for($i=0; $i<count($p); $i++) {
    $p = array_merge($p, glob("{$p[$i]}/*", GLOB_ONLYDIR)); //将本级子目录加入待遍历的目录
    $a = preg_grep('/\.(jpeg|jpg|png|gif)/i', glob("{$p[$i]}/*")); //读取本级目录列表,并过滤出图片文件名
    foreach(array_chunk($a, 50) as $t) {
      $v = join("'),('", $t);
      $sql = "INSERT INTO `#@__uploads` (path) VALUES ('$v')"; //构造批量插入指令
      $dosql->ExecNoneQuery($sql);
    }
  }
}
这是一次性工作,要休息干什么?

#7


引用 6 楼 xuzuning 的回复:
function traversing($path) {
  $p = array($path); //待遍历的目录
  for($i=0; $i<count($p); $i++) {
    $p = array_merge($p, glob("{$p[$i]}/*", GLOB_ONLYDIR)); //将本级子目录加入待遍历的目录
    $a = preg_grep('/\.(jpeg|jpg|png|gif)/i', glob("{$p[$i]}/*")); //读取本级目录列表,并过滤出图片文件名
    foreach(array_chunk($a, 50) as $t) {
      $v = join("'),('", $t);
      $sql = "INSERT INTO `#@__uploads` (path) VALUES ('$v')"; //构造批量插入指令
      $dosql->ExecNoneQuery($sql);
    }
  }
}
这是一次性工作,要休息干什么?

终于可以了,感谢版主。其实我是想做本地图片文件与数据库对比,然后找出不存在的,删除,这样的一个功能。
上次你告诉我将读到的图片名保存到数据库,然后用 sql 指令完成比较。
我现在把本地的所有图片存到数据库uploads表了,与数据库的另一个表imgs表,对比,它们2个表的结构是一样的,只有id 和 path 2个字段。有最快的指令完成比较吗?

我现在是这样比较的
if(!strpos($imgs['path'],$uploads['path']))
{
...//不同的显示在这里。
}
这样的对比我发现感觉也没那么快,还有其他办法吗。

#8


使用预执行SQL,应该会好很多,比如PDO的prepare()
<?php
$sql="insert into '#@__uploads' (path) values(:file);";//假设$db是外部你的PDO连接对象
$myInsert=$db->conn->prepare($sql);
function traversing($path)
{
$path=realpath($path);
    if(is_dir($path)){
$file=opendir($path);
while($f=readdir($file)){
if($f==='.' || $f==='..')
{

}else if(is_dir($f)){
traversing("{$path}\\{$f}");
}else{
$pro=strtolower(substr($f, -4));
if(stripos($pro,'.jpg')!==false || stripos($pro,'.gif')!==false || stripos($pro,'.png')!==false){
$myInsert->bindValue(":file",$f);
$myInsert->execute();
}else{
$pro=strtolower(substr($f, -5));
if(stripos($pro,'.jpeg')!==false){
$myInsert->bindValue(":file",$f);
$myInsert->execute();
}
}
}
}
    }
return true;
}
traversing('upload');
?>

#9


#获取有用到的
select * from uploads a, imgs b where a.path=b,path

#获取没有用到的
select * from uploads a left join imgs b on a.path=b.path where b.id is null 

#获取没有用到的
select * from uploads where path not in (select path from imgs)
 

#1


才几千条,先扫描后入库,很快的

#2


换个写法,不用递归
function traversing($path) {
  $p = array($path); //待遍历的目录
  for($i=0; $i<count($p); $i++) {
    $p = array_merge($p, glob("{$p[$i]}/*", GLOB_ONLYDIR)); //将本级子目录加入待遍历的目录
    $a = preg_grep('/\.(jpeg|jpg|png|gif)/i', glob("{$p[$i]}/*")); //读取本级目录列表,并过滤出图片文件名
    $v = join("'),('", $a);
    $sql = "INSERT INTO `#@__uploads` (path) VALUES ('$v')"; //构造批量插入指令
    $dosql->ExecNoneQuery($sql);
  }
}

在递归写法中,每一层读取的目录列表($curr)所占的内存,要等到本层返回时才会被释放
这显然是很耗内存的
一条条的判断、插入,也不如批量插入来的快

#3


引用 2 楼 xuzuning 的回复:
换个写法,不用递归
function traversing($path) {
  $p = array($path); //待遍历的目录
  for($i=0; $i<count($p); $i++) {
    $p = array_merge($p, glob("{$p[$i]}/*", GLOB_ONLYDIR)); //将本级子目录加入待遍历的目录
    $a = preg_grep('/\.(jpeg|jpg|png|gif)/i', glob("{$p[$i]}/*")); //读取本级目录列表,并过滤出图片文件名
    $v = join("'),('", $a);
    $sql = "INSERT INTO `#@__uploads` (path) VALUES ('$v')"; //构造批量插入指令
    $dosql->ExecNoneQuery($sql);
  }
}

在递归写法中,每一层读取的目录列表($curr)所占的内存,要等到本层返回时才会被释放
这显然是很耗内存的
一条条的判断、插入,也不如批量插入来的快

目录文件少的可以,文件多的目录没有遍历进去,这是为什么呢?第一个文件夹的能入库,第二个文件夹的不能入库。
php 如何能让代码一个一个执行而不占用CPU和内存呢?
php 如何能让代码一个一个执行而不占用CPU和内存呢?
php 如何能让代码一个一个执行而不占用CPU和内存呢?


#4


文件太多了!
可用 array_chunk 将数组切成小段,分别处理

#5


引用 4 楼 xuzuning 的回复:
文件太多了!
可用 array_chunk 将数组切成小段,分别处理

array_chunk 不懂怎么切呢,可以让代码休息10秒后继续的办法吗?感觉那样没那么占内存。

#6


function traversing($path) {
  $p = array($path); //待遍历的目录
  for($i=0; $i<count($p); $i++) {
    $p = array_merge($p, glob("{$p[$i]}/*", GLOB_ONLYDIR)); //将本级子目录加入待遍历的目录
    $a = preg_grep('/\.(jpeg|jpg|png|gif)/i', glob("{$p[$i]}/*")); //读取本级目录列表,并过滤出图片文件名
    foreach(array_chunk($a, 50) as $t) {
      $v = join("'),('", $t);
      $sql = "INSERT INTO `#@__uploads` (path) VALUES ('$v')"; //构造批量插入指令
      $dosql->ExecNoneQuery($sql);
    }
  }
}
这是一次性工作,要休息干什么?

#7


引用 6 楼 xuzuning 的回复:
function traversing($path) {
  $p = array($path); //待遍历的目录
  for($i=0; $i<count($p); $i++) {
    $p = array_merge($p, glob("{$p[$i]}/*", GLOB_ONLYDIR)); //将本级子目录加入待遍历的目录
    $a = preg_grep('/\.(jpeg|jpg|png|gif)/i', glob("{$p[$i]}/*")); //读取本级目录列表,并过滤出图片文件名
    foreach(array_chunk($a, 50) as $t) {
      $v = join("'),('", $t);
      $sql = "INSERT INTO `#@__uploads` (path) VALUES ('$v')"; //构造批量插入指令
      $dosql->ExecNoneQuery($sql);
    }
  }
}
这是一次性工作,要休息干什么?

终于可以了,感谢版主。其实我是想做本地图片文件与数据库对比,然后找出不存在的,删除,这样的一个功能。
上次你告诉我将读到的图片名保存到数据库,然后用 sql 指令完成比较。
我现在把本地的所有图片存到数据库uploads表了,与数据库的另一个表imgs表,对比,它们2个表的结构是一样的,只有id 和 path 2个字段。有最快的指令完成比较吗?

我现在是这样比较的
if(!strpos($imgs['path'],$uploads['path']))
{
...//不同的显示在这里。
}
这样的对比我发现感觉也没那么快,还有其他办法吗。

#8


使用预执行SQL,应该会好很多,比如PDO的prepare()
<?php
$sql="insert into '#@__uploads' (path) values(:file);";//假设$db是外部你的PDO连接对象
$myInsert=$db->conn->prepare($sql);
function traversing($path)
{
$path=realpath($path);
    if(is_dir($path)){
$file=opendir($path);
while($f=readdir($file)){
if($f==='.' || $f==='..')
{

}else if(is_dir($f)){
traversing("{$path}\\{$f}");
}else{
$pro=strtolower(substr($f, -4));
if(stripos($pro,'.jpg')!==false || stripos($pro,'.gif')!==false || stripos($pro,'.png')!==false){
$myInsert->bindValue(":file",$f);
$myInsert->execute();
}else{
$pro=strtolower(substr($f, -5));
if(stripos($pro,'.jpeg')!==false){
$myInsert->bindValue(":file",$f);
$myInsert->execute();
}
}
}
}
    }
return true;
}
traversing('upload');
?>

#9


#获取有用到的
select * from uploads a, imgs b where a.path=b,path

#获取没有用到的
select * from uploads a left join imgs b on a.path=b.path where b.id is null 

#获取没有用到的
select * from uploads where path not in (select path from imgs)