如何利用Composer的并行下载插件提高安装速度?(极限优化)

3次阅读

composer install 慢的根本原因是默认单线程串行处理依赖,i/o 和阻塞占时超70%;升级至2.2+、禁用钩子插件、启用–concurrency并发、优化镜像源与文件系统写入可显著提速。

如何利用Composer的并行下载插件提高安装速度?(极限优化)

composer install 为什么慢得像在编译内核?

根本原因不是网络,而是 PHP 进程串行解析 composer.lock、逐个发起 http 请求、解压、校验、写入磁盘——尤其当依赖超过 50 个时,I/O 等待和单线程阻塞会吃掉 70% 以上时间。

官方 composer install 默认不并发,哪怕你机器有 16 核、千兆宽带,它也只开 1 个 HTTP 连接、1 个解压进程。

实操建议:

  • 别碰 COMPOSER_PROCESS_TIMEOUT 或盲目调高 memory_limit——这解决不了并发瓶颈
  • 确认你用的是 Composer 2.2+(composer --version),低于此版本不支持原生并行下载
  • 禁用所有非必要插件:composer global config -g disable-tls true 无意义,反而危险;真正要关的是 composer-unusedphpstan-extension-installer 这类钩子型插件,它们会在每个包安装后触发,放大串行延迟

启用 composer-parallel-install 是最直接的提速方式

这不是第三方“加速插件”,而是 Composer 官方在 2.2 中合并的内置能力,通过 --concurrency 控制并发数,底层复用 curl multi 和进程池,无需额外安装扩展。

常见错误现象:加了 --concurrency=8 但速度没变化 → 很可能是你的镜像源(如阿里云、腾讯云)本身限流或不支持 HTTP/2 多路复用,导致并发请求被排队堵死。

实操建议:

  • 优先用官方源测试基准速度:composer config -g repo.packagist composer https://packagist.org
  • 再执行:composer install --concurrency=6 --no-interaction --no-progress--concurrency 值设为 CPU 核心数 × 1.5,但不超过 12)
  • 若仍卡在某个包(比如 symfony/console),用 strace -e trace=openat,connect,write -p $(pgrep -f "composer install") 看是否在反复重试 DNS 或 TLS 握手——这时要换 DNS(如 1.1.1.1)或加 export COMPOSER_NO_TLS=1(仅限内网可信环境)

vendor 目录写入慢?关掉 fsync 和杀毒实时扫描

Composer 并行下载快了,但解压完往 vendor/ 写文件时可能又卡住——特别是 macos APFS 或 windows NTFS + 实时防病毒软件(如 Windows Defender、腾讯电脑管家)会同步拦截每个 file_put_contents 调用。

性能影响比想象中大:一个 2MB 的

.tar` 包解压成数百个小文件,fsync 触发次数 ≈ 文件数,每秒写入从 120MB 掉到 8MB。</p> <p>实操建议:</p> <ul> <li>linux/macOS:临时关闭 sync:<code>composer install --concurrency=8 --no-scripts && sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

(仅用于 CI 环境,开发机慎用)

  • Windows:进 Windows Defender 设置 → “病毒和威胁防护” → “实时保护” → 暂时关闭;或把项目目录加到排除列表
  • 统一规避方案:改用 composer install --no-plugins --no-scripts,后续用 composer run-script post-install-cmd 单独触发脚本——避免脚本在并发写入中途干扰
  • CI 环境下进一步压榨:缓存 lock + 并行 + 分层 vendor

    github Actions / gitlab CI 每次都重装 vendor 是最大浪费。单纯缓存 vendor/ 目录不可靠(不同 PHP 版本、扩展差异会导致运行时错误),必须配合 composer.lock 和平台约束。

    容易踩的坑:用 cache: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 却没锁死 PHP 版本 → 缓存命中后 ext-redis 版本不一致,composer install 静默跳过但运行时报 class Redis not found

    实操建议:

    • composer.json 显式声明:"config": { "platform": { "php": "8.2.12" } }
    • CI 脚本分三步:
      composer install --dry-run --no-plugins 验证 lock 兼容性
      composer install --concurrency=10 --no-interaction --no-progress --no-scripts
      composer run-script post-install-cmd
    • 不要缓存整个 vendor/,缓存 ~/.composer/cache + composer.lock 哈希即可,体积小、命中率高、无污染风险

    真正的极限优化不在参数调多大,而在于让每一步都可预测、可跳过、不互相拖累。比如一个 post-install-cmd 里执行 php-cs-fixer fix,它会等全部 vendor 写完才启动,而这个过程本身是单线程的——这种地方,比改 --concurrency 值重要十倍。

    text=ZqhQzanResources