与本机 Windows NPM/Yarn 处理相比,为什么 WSL 极其缓慢?

WrR*_*ThY 132 ubuntu npm windows-subsystem-for-linux yarnpkg wsl-2

我最近经常使用 WSL,因为我需要一些本机 UNIX 工具(并且模拟器还不够好)。我注意到使用 NPM/Yarn 时的速度差异令人难以置信。

我进行了一个简单的测试,证实了我的感受。测试正在运行npx create-react-app my-test-app,WSL 结果是Done in 287.56s.GitBash 完成的Done in 10.46s.

这并不是全部情况,因为两种情况下的感知时间都更长,但即使基于此 - 某个地方也存在一个大问题。我只是不知道在哪里。我正在从事的项目使用了数十个库,即使更改其中一个也需要几分钟而不是几秒钟。

这是我可以解决的问题吗?如果是这样——去哪里寻找线索?

附加信息:

  • 我的处理器:AMD Ryzen 7 5800H 处理器,带 Radeon Graphics,3201 Mhz,8 核,16 个逻辑处理器

  • 我运行的是 Windows 11,并且系统和 WSL 均已更新到最新版本。选择的系统是Ubuntu 20.04

  • 我见过一些有点类似的问题,比如'npm install' 在 Windows 上速度非常慢,但它们根本不接触 WSL(而且我的纯 Windows NPM 工作得很快)。

  • 这个问题不仅限于 NPM,也适用于 Yarn

  • 我遇到的另一个问题是文件监视没有发生(我需要在每次更改时重新启动服务器)。在某些应用程序中我没有收到任何错误,有时我会收到以下错误:

    Watchpack Error (initial scan): Error: EACCES: permission denied, lstat '/mnt/c/DumpStack.log.tmp'
    Watchpack Error (initial scan): Error: EACCES: permission denied, lstat '/mnt/c/hiberfil.sys'
    Watchpack Error (initial scan): Error: EACCES: permission denied, lstat '/mnt/c/pagefile.sys'
    Watchpack Error (initial scan): Error: EACCES: permission denied, lstat '/mnt/c/swapfile.sys'
    
    Run Code Online (Sandbox Code Playgroud)
  • npm start在一个空的(新初始化的)中create-react-app需要很长时间才能在 WSL 中的浏览器中渲染某些内容,并且当从 GitBash 执行时 - 我可以在 2-4 秒内看到内容

  • 有可能这纯粹是一个 WSL 问题,但在使用 NPM/Yarn 时它是最痛苦的

Not*_*1ds 165

既然您提到从 Git Bash 中执行相同的文件(具有适当的性能),我将在这里做出一个假设。

如果您的文件存储在/mnt/c(又名C:,或/C Bash 下)或任何其他 Windows 驱动器上,则这将得到解释(也是预期的),因为它们可能需要由 Git Bash 访问。

WSL2 使用 9P 协议访问 Windows 驱动器,目前(参见脚注)与以下相比速度非常慢:

  • 本机 NTFS(显然)
  • WSL2 使用的虚拟磁盘上的 ext4 文件系统
  • 甚至 WSL1 与 Windows 驱动器的性能

我见过一个git clone大型存储库(WSL2 Linux 内核 Github)在 Windows 驱动器上的 WSL2 上需要 8 分钟,但在根文件系统上只需要几秒钟。

两种可能性:

  • 如果可能(对于大多数 Node 项目都是如此),请将您的 WSL 转换为带有wsl --set-version <distroname> 1. 我总是建议使用以下命令进行备份wsl --export

    而且由于您无论如何都要进行备份,因此您也可以通过将您的备份添加为(作为最后一个参数)来创建实例的副本。WSL1 和 WSL2 都有其用途,您可能会发现保留两者很有帮助。wsl --import--version 1

    有关确切语法的更多详细信息,请参阅此答案。

  • 或者只是将项目移动到 WSL 根目录下的某个位置,例如/home/username/src/.


脚注

根据最近的发展,这一领域可能有改善的希望。9P 的补丁已在上游发布,据报道可显着提升性能。请参阅此 Github 线程评论(以及父线程)以获取更多信息。

  • 嘿,首先 - 非常感谢您的全面回答。是的 - 我的所有文件都存储在“/mnt/c”下。我尝试了您的第二个解决方案 - 它在终端中的运行速度与预期一样快,但是当我第一次加载 `create-react-app` 项目 [IntelliJ Ultimate] 时,IDE 冻结了。有趣的是,第二次运行成功了 - 我将用我的实际项目进行更多测试。当谈到切换到 WSL1 时 - 我隐约记得我需要升级,因为 WSL1 缺少 WSL2 所具有的一些功能(我正在使用 Solana dev 的 BPF 编译器运行 Rust),所以我不能这样做 (5认同)
  • @WrRaThY 这是用于跟踪的主要[问题](https://github.com/microsoft/WSL/issues/4197),虽然我已阅读 Microsoft 团队的声明,表示他们对性能不满意,但我除了 9P 中可能缺乏缓存支持之外,我不知道提到了根本原因(但我还没有阅读有关该问题的所有 350 多条评论)。 (2认同)
  • 这解释了为什么 WSL 中的 NetBeans 速度很慢。将 NetBeans 文件复制到 Linux 目录,速度相当快。谢谢,太棒了! (2认同)

tym*_*tam 83

基于@notthedr01ds 的回复。

如果您查看 Microsoft 的比较 WSL 1 和 WSL 2,就会发现 WSL2 中的 “跨操作系统文件系统的性能”明显更差。

WS1 和 WSL2 的比较来自 Comparing WSL 1 and WSL 2

我的案例属于使用 WSL 1 而不是 WSL 2 的例外

  • 您的项目文件必须存储在 Windows 文件系统中。WSL 1 可以更快地访问从 Windows 挂载的文件。
    • 如果您将使用 WSL Linux 发行版访问 Windows 文件系统上的项目文件,并且这些文件无法存储在 Linux 文件系统上,则通过使用 WSL 1,您将在操作系统文件系统上实现更快的性能。

这意味着我需要切换到版本 1。

wsl --set-version Ubuntu 1
Conversion in progress, this may take a few minutes...
Conversion complete.
Run Code Online (Sandbox Code Playgroud)

之前测试

>time git status
...
real    0m6.436s
user    0m0.055s
sys     0m36.380s
Run Code Online (Sandbox Code Playgroud)

之后测试

> time git status
...
real    0m0.126s
user    0m0.016s
sys     0m0.641s
Run Code Online (Sandbox Code Playgroud)

  • 根据 https://vxlabs.com/2019/12/06/wsl2-io-measurements/ 的说法,最佳性能是 WSL-2 在 ext4 上运行(即在 WSL-2 内部)而不是在外部(即 NTFS)上运行。他们说它比 lxfs 或 NTFS 上的 WSL-1 更快。 (8认同)

Fra*_*ood 9

我在 Windows 11 上使用 WSL 2 时遇到了完全相同的问题。WSL 使用两个文件系统:WSL/Linux 文件系统和 Windows 文件系统。

令人困惑的是,默认情况下,WSL 提示符以

/mnt/c/Users/<username>
Run Code Online (Sandbox Code Playgroud)

当您在此处执行 git 克隆时,会发生文件被下载到 Windows 文件系统中的情况。如果您在 Windows 中导航到 Users/username 目录,您将在这里找到所有文件。文件系统之间的交互是通过共享(9P 协议)完成的。这太慢了。因此,如果您位于“mnt”的子目录中,则您没有使用 WSL 文件系统。

确保启动 WSL 后进入 WSL 文件系统,例如您的主目录

$ cd
Run Code Online (Sandbox Code Playgroud)

如果您在此处克隆并开始构建,您将获得您期望的性能。

https://learn.microsoft.com/en-us/windows/wsl/filesystems


编辑:

我确保 wsl 始终在本地文件系统而不是 wsl 共享上启动。你可以对任何你喜欢的目录执行此操作,我喜欢从我的 git 文件夹开始:

echo 'cd ~/git' >>~/.bashrc 
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,“cd”是“cd ~”的缩写;) (2认同)