Mac 上装 PyTorch 这件事,说简单也简单,说坑也多。尤其是换了 M 系列芯片之后,网上大量教程还停留在 Intel 时代,照着敲命令,要么装出来跑在 CPU 上慢得离谱,要么 import 就报架构不匹配,要么 conda 环境里 Python 版本和 torch 版本互相打架。我自己前前后后在几台 M 芯片的机器上折腾过好几轮,从最早 M1 刚出时生态一片荒芜,到现在 MPS 后端基本可用,踩过的坑基本能凑成一本小册子。这篇就把 Mac M 系列芯片安装配置 PyTorch 的完整路径拆开讲清楚:从环境隔离、Python 版本选择、安装方式对比,到 MPS 加速的验证、常见报错的排查,再到实际训练时那些官方文档不会明说的性能细节。不管你是刚拿到 Mac 想跑第一个深度学习 demo 的新手,还是从 Intel Mac 迁移过来、发现老环境跑不动的研究者,都能照着这篇从头走一遍,少走弯路。
1. 先搞清楚 M 系列芯片装 PyTorch 到底特殊在哪
1.1 统一内存架构带来的机会与限制
M 系列芯片最核心的变化是统一内存架构(Unified Memory Architecture)。传统 PC 上,CPU 有自己的一块内存,GPU 有独立的显存,数据在两者之间搬运要走 PCIe 总线,这个搬运开销在训练小模型时甚至能占到相当比例。M 系列把 CPU、GPU、神经引擎放在同一块芯片上,共享同一池内存,理论上 GPU 可以直接访问 CPU 写好的数据,省掉了显式拷贝。
这个特性对 PyTorch 用户意味着两件事。好消息是,你不需要像在独立显卡机器上那样时刻盯着显存够不够,模型和数据共享系统内存,16G 内存的机器跑一些中等规模的模型是可行的。坏消息是,共享内存不等于无限内存,系统本身、浏览器、IDE 都在抢同一池资源,一旦内存吃紧,系统会开始疯狂 swap,训练速度断崖式下跌,严重时直接卡死。我在一台 16G 的机器上跑 batch size 稍大的图像分类,监控里看到内存压力变黄,loss 曲线立刻变得一顿一顿的,这就是 swap 在拖后腿。
另一个限制是 MPS 后端的能力边界。MPS 是 Metal Performance Shaders 的缩写,是苹果提供的 GPU 计算框架,PyTorch 通过它来调用 M 系列芯片的 GPU。它不像 CUDA 那样成熟,部分算子没有 GPU 实现,遇到这种情况 PyTorch 会回退到 CPU,或者直接报错。所以你在 M 系列上跑模型,不能假设“有 GPU 就一定能加速”,得实际验证。
1.2 为什么不能照搬 Intel Mac 的老教程
Intel Mac 时代的 PyTorch 安装逻辑很简单:装个 Python,pip install torch,跑在 CPU 上,完事。那时候 Mac 基本没有可用的 GPU 加速路径(AMD 显卡的支持也很有限),大家对 Mac 跑深度学习的预期就是“能跑就行,别指望快”。
M 系列芯片出来后,情况变了,但网上大量教程没跟上。常见的过时做法包括:用系统自带的 Python 直接 pip 安装、不建虚拟环境、装完不验证 device、以及最坑的一种——装了个老版本 torch,那个版本压根不支持 MPS,跑起来还是 CPU,用户还以为自己已经用上 GPU 了。还有一种情况是用了某些第三方源的非官方 wheel,装完 import 报错,排查半天发现是架构不匹配(x86_64 的包装在 arm64 的 Python 上)。
所以这篇的路线是:先隔离环境,再选对 Python 版本,用官方渠道装最新稳定版 torch,最后强制验证 MPS 是否真的生效。这四步任何一步偷懒,后面都可能出问题。
1.3 安装方式怎么选:pip、conda 还是官方安装器
三种主流方式各有适用场景,我先把结论摆出来,再解释原因。
| 方式 | 适合人群 | 优点 | 缺点 |
|---|---|---|---|
| pip + venv | 大多数用户,尤其是只做 PyTorch 的 | 轻量、官方 wheel 更新快、MPS 支持及时 | 需要自己管 Python 版本 |
| conda / mamba | 需要多框架共存、依赖复杂项目 | 环境隔离彻底、二进制依赖处理好 | 体积大、有时 torch 版本滞后 |
| 官方安装器(.pkg) | 完全新手 | 图形化、省心 | 灵活性差、不便于多版本管理 |
我个人的偏好是pip + venv,原因是 PyTorch 官方对 pip wheel 的更新最及时,MPS 相关的修复往往先在 pip 渠道体现。conda 渠道的 torch 有时会慢半拍,而且 conda 环境体积动辄几个 G,对存储紧张的机器不太友好。当然,如果你的项目还要装一堆科学计算库、且版本约束复杂,conda 的依赖求解确实省心,那就用 conda,但要注意指定pytorch官方 channel。
提示:无论用哪种方式,都不要往系统自带的 Python 里装包。macOS 自带的 Python 是给系统工具用的,污染了之后排查起来非常痛苦。
2. 环境准备:Python 版本、包管理器与虚拟环境
2.1 Python 版本怎么选才不踩坑
PyTorch 对 Python 版本有明确的支持范围,装之前先确认。以近两年的稳定版为例,官方通常支持 Python 3.9 到 3.12 这个区间,太老的版本(3.8 及以下)新 torch 不支持,太新的版本(比如刚发布的 3.13)可能还没有对应的 wheel,pip 会尝试从源码编译,在 Mac 上编译 torch 是场灾难,动辄半小时起步还大概率失败。
我的建议是选一个处于支持区间中段、且生态兼容性最好的版本,目前来看 3.10 或 3.11 是比较稳的选择。这两个版本既被主流科学计算库广泛支持,又不会因为太新而缺 wheel。如果你机器上已经有 3.12 且用着没问题,也不必降级,装之前去 PyTorch 官网的 get-started 页面确认一下当前稳定版是否提供对应 wheel 即可。
怎么查看当前 Python 版本:
python3 --version如果版本不合适,别去动系统 Python,用包管理器装一个独立的。Mac 上装 Python 最省心的方式是 Homebrew:
# 安装 Homebrew(如果还没装) /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # 安装指定版本的 Python brew install python@3.11装完之后,python3.11这个命令就可用了。注意 Homebrew 装的 Python 路径通常在/opt/homebrew/bin/(Apple Silicon 的默认前缀),而不是 Intel 时代的/usr/local/bin/,这个差异在配置 PATH 时要注意。
2.2 虚拟环境:为什么必须做,怎么做
虚拟环境的作用是把项目依赖隔离开,避免 A 项目要 torch 2.0、B 项目要 torch 2.3 时互相打架。Python 自带的venv模块就够用,不需要额外装 virtualenv。
创建和激活的完整流程:
# 在项目目录下创建虚拟环境,命名为 .venv(约定俗成的名字) python3.11 -m venv .venv # 激活(zsh 是 macOS 默认 shell) source .venv/bin/activate # 确认激活成功,命令行前缀会出现 (.venv) which python # 应该输出类似 /Users/xxx/your_project/.venv/bin/python激活后,python和pip都指向虚拟环境内的版本,这时候装什么都只影响这个环境。退出用deactivate。
这里有个细节很多人忽略:创建 venv 时用的 Python 版本,决定了这个环境的 Python 版本,之后在环境里 pip 装包都是基于这个版本。所以第一步选对 Python 版本很关键,选错了只能删掉.venv重建。
注意:如果你用 zsh 且装了 oh-my-zsh 之类的框架,有时激活 venv 后提示符没变化,容易误以为没激活。用
which python确认最可靠,别只看提示符。
2.3 升级 pip 与基础工具链
装 torch 之前先把 pip 升到较新版本,老版本 pip 在解析 wheel 的架构标签时可能出问题,尤其是在 arm64 机器上装包时,老 pip 有时会错误地拉取 x86_64 的包。
python -m pip install --upgrade pip setuptools wheelsetuptools和wheel也一起升,某些包在安装时需要它们来构建。这一步很快,但能省掉后面不少莫名其妙的报错。
另外确认一下你的机器架构,确保装的是 arm64 版本:
uname -m # Apple Silicon 应该输出 arm64如果这里输出的是x86_64,说明你的终端跑在 Rosetta 转译模式下,这种情况下装的 Python 和包都是 x86_64 架构,性能会打折,而且 MPS 可能不可用。解决办法是确保终端本身是原生 arm64 模式运行,检查终端的“使用 Rosetta 打开”选项是否被勾选(在 Finder 里右键终端 App -> 显示简介),取消勾选后重启终端。
3. 安装 PyTorch:官方渠道与版本选择
3.1 用官方命令安装稳定版
最稳妥的方式是去 PyTorch 官网的 get-started 页面,选择 Mac、pip、Python 对应的选项,它会生成一条安装命令。以近期的稳定版为例,命令大致是:
pip install torch torchvision torchaudio在 Mac 上,PyTorch 的 pip wheel 已经内置了 MPS 支持,不需要额外装什么 CUDA 工具包(那是 N 卡的事)。装完之后 torch 会自动检测到 M 系列芯片的 GPU 能力。
如果你需要固定某个版本(比如项目要求 torch 2.2),可以指定版本号:
pip install torch==2.2.0 torchvision==0.17.0 torchaudio==2.2.0版本对应关系很重要,torch、torchvision、torchaudio 三者的版本是配套发布的,混装容易出现 ABI 不兼容。最省事的做法是不指定版本,让 pip 装最新稳定版,三个包一起装,pip 会自动选配套的组合。
安装过程会下载几百 MB 的 wheel,取决于网速,几分钟到十几分钟不等。装完后验证:
python -c "import torch; print(torch.__version__)"能打印出版本号就说明装成功了。但这只是第一步,装成功不等于 GPU 可用,下一节专门验证 MPS。
3.2 关于 nightly 版本:什么时候该用,什么时候别碰
PyTorch 有 nightly 构建渠道,包含最新的算子实现和 bug 修复,MPS 后端的一些新特性往往先在 nightly 里出现。但 nightly 的稳定性没有保证,可能今天能跑明天就崩。
我的建议是:除非你遇到了稳定版里明确存在的 MPS bug,且确认 nightly 已修复,否则不要用 nightly。日常开发和跑实验,稳定版足够。如果你确实需要试 nightly:
pip install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cpu注意 Mac 的 nightly 渠道标签是cpu,这不是说只能用 CPU,而是苹果的 MPS 支持打包在这个渠道里,别被名字误导。装完记得记录版本号,出问题时方便回滚。
3.3 验证 MPS 是否真正可用
这是整个安装流程里最关键的一步,也是最多人翻车的地方。装完 torch 后,跑这段代码:
import torch print("PyTorch 版本:", torch.__version__) print("MPS 后端是否可用:", torch.backends.mps.is_available()) print("MPS 是否已构建:", torch.backends.mps.is_built()) if torch.backends.mps.is_available(): device = torch.device("mps") print("使用设备:", device) else: device = torch.device("cpu") print("MPS 不可用,回退到 CPU")三个输出要一起看:
is_built()为 True,说明这个 torch 版本编译时包含了 MPS 支持;is_available()为 True,说明当前机器和系统版本满足 MPS 运行条件;- 两者都为 True,才能放心用
mps设备。
如果is_built()是 True 但is_available()是 False,常见原因是 macOS 版本太老(MPS 需要 macOS 12.3 及以上),或者跑在 Rosetta 模式下。如果is_built()就是 False,那说明装的 torch 版本压根不带 MPS,得升级 torch。
再做一个实际计算的验证,确保不只是“报告可用”,而是真能算:
import torch device = torch.device("mps") x = torch.randn(1000, 1000, device=device) y = torch.randn(1000, 1000, device=device) z = x @ y print("矩阵乘法结果形状:", z.shape) print("计算设备:", z.device)这段能跑通且输出device='mps:0',才算真正用上了 GPU。我见过有人只看了is_available()就以为万事大吉,结果实际训练时某个算子不支持,报错才发现问题,所以这一步的实算验证别省。
4. MPS 加速实战:从能跑到跑得好
4.1 把模型和数据搬到 MPS 上的正确姿势
PyTorch 的设备管理逻辑很统一,MPS 和 CUDA 的用法几乎一样,都是通过.to(device)搬运。标准写法:
import torch import torch.nn as nn device = torch.device("mps" if torch.backends.mps.is_available() else "cpu") # 模型搬到设备 model = nn.Sequential( nn.Linear(784, 256), nn.ReLU(), nn.Linear(256, 10) ).to(device) # 数据搬到设备 inputs = torch.randn(64, 784).to(device) labels = torch.randint(0, 10, (64,)).to(device) # 前向、损失、反向 outputs = model(inputs) loss = nn.CrossEntropyLoss()(outputs, labels) loss.backward() print("loss:", loss.item())这里有个容易忽略的点:优化器状态和模型参数要在同一设备上。如果你先创建优化器再把模型搬到 MPS,优化器里缓存的参数引用可能还指向 CPU,导致更新时报设备不匹配。正确顺序是先.to(device)再创建优化器,或者创建后确认参数设备一致。
另一个细节是 loss 的.item()调用。在 MPS 上,把标量 tensor 转成 Python 数值会触发一次同步,频繁调用(比如每个 batch 都打印 loss)会拖慢训练。建议累积若干 step 再打印,或者用 tensorboard 之类的工具异步记录。
4.2 那些在 MPS 上会报错的算子与规避方法
MPS 后端不是 CUDA 的完整替代,部分算子没有 GPU 实现。常见的踩坑场景:
- 某些稀疏操作:稀疏矩阵相关算子在 MPS 上支持不全,遇到报错可以先把相关张量转回 CPU 计算再转回来;
- 部分归一化层的特殊模式:比如某些带复杂统计的归一化,可能回退或报错;
- 自定义算子的 backward:如果你用了自定义 autograd Function,backward 里的某些操作可能没有 MPS 实现。
遇到NotImplementedError或类似“operator not implemented for MPS”的报错,处理思路是:先定位是哪个算子,然后要么换等价实现,要么把那一小段逻辑放到 CPU 上算。PyTorch 提供了环境变量可以强制某些操作回退:
export PYTORCH_ENABLE_MPS_FALLBACK=1设置后,没有 MPS 实现的算子会自动回退到 CPU,而不是直接报错。这个变量对调试很有用,但不建议长期开着,因为回退意味着数据在 CPU 和 GPU 之间搬运,性能损失明显,而且你很难察觉哪些操作偷偷跑了 CPU。正确做法是用它定位问题,然后针对性改写代码。
提示:设置
PYTORCH_ENABLE_MPS_FALLBACK=1后,建议在代码里加日志,或者用 profiler 看看哪些操作耗时异常,确认回退没有发生在热点路径上。
4.3 性能调优:batch size、数据类型与内存监控
M 系列芯片的统一内存让“显存不够”这个问题变得模糊,但性能调优的逻辑和独显机器类似,核心是让 GPU 保持忙碌、减少数据搬运。
batch size 的选择要结合内存。统一内存意味着 batch 开太大,系统整体内存吃紧,swap 一开,训练速度反而下降。我的经验是从一个保守值开始(比如图像分类 32 或 64),用活动监视器盯着内存压力,逐步往上加,直到内存压力变黄之前停下。别迷信“越大越好”,在共享内存架构上,留出余量给系统和其他进程更明智。
数据类型方面,MPS 支持 float16,混合精度训练能明显提速并省内存。PyTorch 的torch.autocast可以用:
with torch.autocast(device_type="mps", dtype=torch.float16): outputs = model(inputs) loss = criterion(outputs, labels)不过要注意,autocast 在 MPS 上的成熟度不如 CUDA,某些模型可能出现数值不稳定(loss 变 NaN)。如果遇到,先关掉 autocast 确认是精度问题,再考虑只对部分层用半精度,或者用torch.float32稳一手。
内存监控方面,Mac 自带的活动监视器就够用,重点看“内存压力”图表,绿色表示充裕,黄色表示开始吃紧,红色就是危险了。命令行可以用vm_stat看 swap 情况。训练时如果发现内存压力持续黄色以上,优先降 batch size 或减小模型,别硬扛。
4.4 一个完整的训练循环示例
把上面的要点串起来,给一个可直接跑的最小训练循环,方便你对照自己的代码:
import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset # 设备选择 device = torch.device("mps" if torch.backends.mps.is_available() else "cpu") print("使用设备:", device) # 造点假数据 X = torch.randn(2000, 20) y = torch.randint(0, 2, (2000,)) dataset = TensorDataset(X, y) loader = DataLoader(dataset, batch_size=64, shuffle=True) # 模型 model = nn.Sequential( nn.Linear(20, 64), nn.ReLU(), nn.Linear(64, 2) ).to(device) criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) # 训练 model.train() for epoch in range(5): total_loss = 0.0 for batch_x, batch_y in loader: batch_x = batch_x.to(device) batch_y = batch_y.to(device) optimizer.zero_grad() out = model(batch_x) loss = criterion(out, batch_y) loss.backward() optimizer.step() total_loss += loss.item() print(f"epoch {epoch+1}, avg loss: {total_loss/len(loader):.4f}")这段代码里几个值得注意的点:数据在循环内逐 batch 搬到设备,而不是一次性全搬(省内存);optimizer.zero_grad()在 backward 之前;loss 累积用.item()但只在每个 epoch 打印一次,减少同步开销。照着这个骨架改自己的模型,基本不会出设备相关的错。
5. 常见报错与排查速查
5.1 安装阶段的典型问题
安装阶段最常见的是架构不匹配和版本冲突。整理成速查表:
| 报错现象 | 可能原因 | 解决方向 |
|---|---|---|
ERROR: Could not find a version that satisfies the requirement torch | Python 版本太新或太老,无对应 wheel | 换 3.10/3.11,或查官网支持矩阵 |
装完 import 报mach-o file, but is an incompatible architecture | 装了 x86_64 的包,跑在 arm64 Python 上 | 确认uname -m为 arm64,重装 |
pip卡在 building wheel 很久 | 没有对应 wheel,在从源码编译 | 换 Python 版本或换安装渠道 |
装完is_built()为 False | torch 版本太老,不含 MPS | 升级到较新稳定版 |
架构不匹配这个坑特别隐蔽,因为报错信息不一定直白。判断方法是看 Python 的架构:
python -c "import platform; print(platform.machine())"输出arm64才对。如果输出x86_64,说明这个 Python 是 Rosetta 下跑的,装的包也会是 x86_64,MPS 大概率不可用。解决办法是重装原生 arm64 的 Python,并确保终端不在 Rosetta 模式。
5.2 运行阶段的 MPS 报错
运行阶段的报错更杂,核心思路是先确认是不是算子不支持,再决定回退还是改写。
遇到NotImplementedError: The operator 'xxx' is not currently implemented for the MPS device,处理流程是:先用PYTORCH_ENABLE_MPS_FALLBACK=1跑一遍,看能不能跑通;能跑通说明就是算子缺失,然后定位这个算子在代码哪里,评估能否用等价算子替换,或者把那一小段搬到 CPU。如果这个算子在热点路径上(每个 batch 都执行),回退的性能损失可能让 GPU 加速失去意义,那就得认真考虑改写。
还有一种报错是内存相关的,比如MPS backend out of memory。虽然统一内存理论上更宽松,但 MPS 后端有自己的内存分配上限,模型太大还是会 OOM。解决办法是降 batch size、用梯度累积模拟大 batch、或者用半精度。梯度累积的写法:
accum_steps = 4 optimizer.zero_grad() for i, (batch_x, batch_y) in enumerate(loader): batch_x, batch_y = batch_x.to(device), batch_y.to(device) out = model(batch_x) loss = criterion(out, batch_y) / accum_steps loss.backward() if (i + 1) % accum_steps == 0: optimizer.step() optimizer.zero_grad()这样等效 batch size 是原来的 4 倍,但峰值内存只按单份 batch 算。
5.3 环境与依赖冲突的排查
依赖冲突往往表现为 import 时报某个底层库找不到或版本不对。排查顺序:先确认当前在正确的虚拟环境里(which python),再pip list看 torch 相关包的版本是否配套,最后看有没有多个 Python 环境互相干扰。
一个高频问题是 torchvision 和 torch 版本不匹配,报错类似RuntimeError: operator torchvision::nms does not exist。这是因为 torchvision 编译时链接的 torch ABI 和当前装的 torch 不一致。解决办法是卸载重装,让 pip 重新解析配套版本:
pip uninstall torch torchvision torchaudio -y pip install torch torchvision torchaudio不指定版本,让 pip 自己选配套组合,通常能解决。如果项目必须固定版本,那就去查 PyTorch 官方的版本对应表,手动对齐三个包的版本号。
注意:卸载重装前先
pip freeze > requirements.txt备份当前环境,万一重装后其他包出问题,方便回滚对照。
6. 一些官方文档不会明说的经验
6.1 关于“MPS 到底比 CPU 快多少”的真实预期
很多人装完 MPS 第一件事就是跑个 benchmark,然后发现某些任务上 GPU 只比 CPU 快一点点,甚至更慢,于是怀疑自己装错了。这其实很正常。MPS 的加速效果高度依赖任务类型:大矩阵乘法、卷积这类并行度高的操作,GPU 优势明显;而小模型、小 batch、或者大量标量操作的任务,GPU 的调度开销可能盖过计算收益,反而不如 CPU。
我的实测体会是:模型越大、batch 越大、计算越密集,MPS 的相对优势越明显。跑一个几层的小 MLP,CPU 和 MPS 差距可能就百分之几十;换成 ResNet 级别的卷积网络、batch 开到 64 以上,差距能拉到数倍。所以别拿玩具模型判断加速效果,要拿你实际要跑的任务来测。
另外,第一次在 MPS 上跑某个操作时会有编译和初始化开销,第一次迭代特别慢是正常的,别把冷启动时间算进平均速度里。测速时先 warmup 几轮,再计时。
6.2 系统版本与 Xcode 命令行工具的隐性依赖
MPS 依赖 macOS 的 Metal 框架,系统版本太老会直接导致is_available()返回 False。MPS 需要 macOS 12.3 及以上,建议保持系统在较新的稳定版。升级系统前记得评估一下项目依赖,大版本升级偶尔会带来工具链变化。
另外,某些 Python 包的安装(尤其是需要编译的)依赖 Xcode 命令行工具。如果遇到编译报错提示缺头文件或编译器,装一下:
xcode-select --install这个命令会弹窗引导安装,装完编译环境就齐了。注意它装的是命令行工具,不是完整的 Xcode,体积小很多,日常够用。
6.3 多项目多版本的隔离策略
如果你同时维护几个项目,对 torch 版本要求不同,光靠 venv 管理会有点累。我的做法是每个项目一个独立 venv,命名带上项目名,比如.venv-projA、.venv-projB,激活时明确指定。配合 direnv 这类工具可以做到进入目录自动激活对应环境,减少手动切换的出错概率。
对于需要频繁切换 Python 版本的情况,可以用 pyenv 管理多个 Python 版本,再在每个版本下建 venv。pyenv 的安装和配置稍微复杂一点,但对多版本共存场景确实方便。不过要注意 pyenv 装的 Python 和 Homebrew 装的可能路径冲突,选一种方式统一管理,别混用。
最后分享一个我踩过的坑:曾经在一个项目里同时用了 conda 和 venv,结果 shell 的 PATH 里 conda 的 base 环境排在前面,导致python指向了 conda 的 Python 而不是 venv 的,装包装到了错误的环境里,排查了半天。教训是一个项目只用一种环境管理方式,并且每次操作前用which python和which pip确认指向,这个习惯能省掉大量玄学问题。
6.4 数据加载的瓶颈别忽视
GPU 加速之后,瓶颈往往会转移到数据加载上。如果 DataLoader 的num_workers设得太小,GPU 会频繁等数据,利用率上不去。Mac 上num_workers的设置和 Linux 略有不同,因为 macOS 的进程启动机制(spawn)比 Linux 的 fork 开销大,worker 开太多反而拖慢。
我的经验是num_workers从 2 或 4 开始试,配合persistent_workers=True避免每个 epoch 重建 worker。同时用pin_memory在 CUDA 上有用,但在 MPS 上意义不大,可以不开。判断数据加载是不是瓶颈,看训练时 GPU 利用率(活动监视器里看 GPU 历史)是否长期偏低,如果是,优先优化数据管道而不是继续调模型。
loader = DataLoader( dataset, batch_size=64, shuffle=True, num_workers=4, persistent_workers=True )这套配置在多数 Mac 项目上表现稳定,worker 数量再往上加收益递减,甚至因为进程开销变慢,建议实测对比后再定。