You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP中如何优化多次filesize()调用针对远程文件系统的执行性能?

PHP远程SMB文件系统filesize调用慢优化方案

核心优化逻辑

原代码性能瓶颈是单次filesize()调用对应一次SMB网络往返,串行执行下总耗时随文件数量线性增长,优化核心是减少网络请求次数或将串行请求改为并行执行。

无需额外扩展方案(优先推荐)

  • 方案1:批量拉取目录元数据(同目录下文件最优)
    利用FilesystemIterator遍历目录时会一次性拉取整个目录下所有文件的元数据,仅产生1次SMB网络往返,远低于逐个调用filesize()的N次开销。
    代码示例:
    $targetDir = '/dir/';
    $minSize = 100;
    // 跳过.和..目录,批量拉取元数据
    $iterator = new FilesystemIterator($targetDir, FilesystemIterator::SKIP_DOTS);
    foreach ($iterator as $fileInfo) {
        $path = $fileInfo->getPathname();
        if ($fileInfo->getSize() > $minSize) {
            echo "{$path} is larger than {$minSize} bytes\n";
        }
    }
    
    // 若只需判断指定路径而非整个目录,可先拉取全目录大小缓存再匹配
    $sizeCache = [];
    foreach ($iterator as $fileInfo) {
        $sizeCache[$fileInfo->getPathname()] = $fileInfo->getSize();
    }
    foreach ($paths as $path => $_) {
        if (isset($sizeCache[$path]) && $sizeCache[$path] > $minSize) {
            echo "{$path} is larger than {$minSize} bytes\n";
        }
    }
    
  • 方案2:系统命令批量查询(跨目录文件适用)
    调用系统ls命令一次查询所有目标文件的大小,仅产生1次网络往返,适合文件分散在多个目录的场景。
    代码示例:
    $minSize = 100;
    $pathArgs = implode(' ', array_map('escapeshellarg', array_keys($paths)));
    exec("ls -l {$pathArgs} | awk '{print \$9, \$5}'", $output);
    foreach ($output as $line) {
        $line = trim($line);
        if (empty($line)) continue;
        list($path, $size) = explode(' ', $line, 2);
        // 路径格式对齐处理
        $path = '/' . ltrim($path, '/');
        if ($size > $minSize) {
            echo "{$path} is larger than {$minSize} bytes\n";
        }
    }
    
  • 方案3:本地缓存复用
    如果目标文件大小更新频率低,可将查询到的文件大小缓存到本地(如APCu、临时文件、数组),缓存有效期内不再重复请求SMB,适合多次重复查询的场景。

扩展方案(性能更高)

  • 方案1:smbclient扩展
    直接调用libsmbclient的原生API批量获取文件元数据,比系统挂载SMB的方式开销更低,支持权限控制、批量操作等能力。
    代码示例:
    // 需先安装smbclient扩展
    $smb = new SmbClient('smb://服务器地址/共享目录/', '用户名', '密码');
    $fileList = $smb->listFiles('/dir/');
    $minSize = 100;
    foreach ($fileList as $file) {
        if (!$file['is_dir'] && $file['size'] > $minSize) {
            $path = "/dir/{$file['name']}";
            echo "{$path} is larger than {$minSize} bytes\n";
        }
    }
    
  • 方案2:Swoole协程并行请求
    利用Swoole协程的异步IO能力,并行发起多个filesize()请求,总耗时等于单次请求的耗时,而非所有请求的耗时总和。
    代码示例:
    // 需先安装swoole扩展
    Co\run(function () use ($paths) {
        $minSize = 100;
        foreach ($paths as $path => $_) {
            Co::create(function () use ($path, $minSize) {
                if (filesize($path) > $minSize) {
                    echo "{$path} is larger than {$minSize} bytes\n";
                }
            });
        }
    });
    

内容的提问来源于stack exchange,提问作者Georg Schölly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 11:48:03