TL;DR:当你在 Windows 上需要批量重命名成千上万个文件(例如给日志文件加日期前缀),单线程Rename-Item会慢到让人怀疑人生。用ForEach-Object -Parallel配合ThrottleLimit,10 万文件重命名耗时从 15 分钟降到 40 秒,且代码只有 3 行。
1. 为什么慢:Rename-Item 的串行瓶颈
PowerShell 的Rename-Item默认是串行执行的,每个文件都要经历一次完整的“获取对象 → 调用 .NET API → 写入元数据”流程。对于机械硬盘或网络驱动器,每次操作还要等待 I/O 完成,导致大量时间浪费在等待上。更坑的是,Get-ChildItem返回的FileInfo对象在管道中传递时,PowerShell 会逐个“解包”,进一步拖慢速度。
实测在 10 万个小文件(平均 4KB)的目录下,用传统方式重命名,耗时 15 分 20 秒,CPU 利用率不到 10%,磁盘队列长度经常为 0——说明根本没打满 I/O,纯粹是等待。
2. 解法:ForEach-Object -Parallel
PowerShell 7+ 提供了ForEach-Object -Parallel,它使用System.Threading.Tasks.Parallel在多个线程上并发处理。配合ThrottleLimit控制并发度,避免过度抢占磁盘。关键点:并行块内只能使用脚本块内定义的变量,外部变量需通过$using:引用。
最小可运行示例:给当前目录下所有.log文件加上日期前缀。
# 需要 PowerShell 7+(pwsh) $prefix = Get-Date -Format "yyyyMMdd" Get-ChildItem -