Composer 2.2+ 的并行下载是内置异步 I/O 调度,基于 PHP 非阻塞 cURL 和事件循环实现单进程并发,复用 TCP 连接、错开 TLS 握手,仅网络层并发,校验解压仍串行。

Composer 2.2+ 的并行下载不是插件,是内置异步 I/O 调度
Composer 原生并发下载从 2.1 开始引入,2.2 起稳定可用,它不依赖多进程或外部工具,而是基于 PHP 的非阻塞 cURL 封装 + 事件循环实现单进程内多路 HTTPS 请求。关键点在于:它复用 TCP 连接(keep-alive)、错开 TLS 握手时间、并行拉取元数据(packages.json)和 dist ZIP,但每个包的校验、解压、写入仍串行执行。
这意味着你看到终端里多个 Downloading https://... 同时滚动,不代表所有环节都并发——只是网络层在跑,磁盘和 PHP 解压仍是瓶颈。所以提速集中在“等待网络响应”阶段,对低带宽、高延迟环境效果最明显;而在 SSD + 千兆内网下,提升可能仅 20%~40%。
-
parallel-downloads和http-max-concurrent-downloads是同一机制的两种配置名,Composer 2.2+ 只认后者,前者设了也无效 - 默认值通常是
6,不是0或3;但很多旧配置残留会把它覆盖成3,导致“开了并行却没感觉” - 并发数不是 CPU 核心数 × 2,而是受远程服务限流约束:GitHub API 未认证请求每小时仅 60 次,阿里云镜像一般允许 50~100 并发,再高就可能触发 429
怎么确认并行真在跑,而不是假象
别信 composer --version 显示 2.2+ 就万事大吉。真实并发是否激活,得看 -vvv 日志里有没有交错出现的 Downloading 行,以及进度数字是否跳跃式前进(比如从 (5/42) 直跳到 (13/42))。
常见“伪并发”现象:
- 始终只有一行
Downloading慢慢推进 → 镜像源响应慢或被限流,不是并发没开 - 进度条卡在某个数字不动超 10 秒 → 可能 DNS 解析失败或 TLS 握手超时,尤其在 CI 环境未配
COMPOSER_NO_TLS=1且网络策略严格时 - 报
file_put_contents(/tmp/...): failed to open stream→ 并发数设太高(如 20),临时文件竞争,建议降到8或10
验证命令:COMPOSER_HTTP_MAX_CONCURRENT_DOWNLOADS=10 composer install -vvv 2>&1 | grep "Downloading" | head -n 5,如果输出里有 3 条以上不同 URL,说明真并发生效。
国内镜像 + 并发配置必须同时做,缺一不可
只调 http-max-concurrent-downloads 到 15,但源还是 https://packagist.org,等于让 15 辆车一起堵在京港澳高速进京口——并发数再高,每辆车等 DNS 和 TLS 的时间还是叠加的。
正确组合:
- 换源必须带结尾
/:composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/(少斜杠会拼出.../composerpackages.json导致 404) - 换源后立刻清缓存:
composer clear-cache,否则旧缓存里的海外 URL 还在偷偷回源 - 全局设并发:
composer config -g http-max-concurrent-downloads 10 - CI 中加
--prefer-dist和--no-autoloader,跳过 PHP 层耗时操作
注意:--prefer-dist 不是并发开关,但它让并发更有效——dist 包体积小、校验快,适合并行拉取;而 source(git clone)无法真正并发,因为 git 协议本身不支持多路复用。
GitHub 限流是并发加速的最大拦路虎
即使你把镜像和并发全配对了,只要项目里含任何直接引用 GitHub 的包(比如 "repo": "github.com/xxx/yyy" 或 dev 分支),Composer 就会绕过镜像,直连 api.github.com。未认证请求每小时最多 60 次,很容易在安装十几个包时就撞上 403 rate limit exceeded。
解法只有两个,且必须选一个:
- 配 GitHub Token:
composer config -g github-oauth.github.com YOUR_TOKEN_HERE,Token 在 GitHub Settings → Developer settings → Personal access tokens 创建,勾选public_repo - 改包源:把 GitHub 地址换成 Gitee 或私有 GitLab 的对应 zip 地址(需保持 tag 一致),例如把
"url": "https://github.com/xxx/yyy/archive/v1.2.3.zip"改成"url": "https://gitee.com/xxx/yyy/repository/archive/v1.2.3.zip"
别指望 github-protocols 或 preferred-install 能绕过这个限制——它们只影响协议协商和安装方式,不改变请求目标域名。











