理系学生日記

おまえはいつまで学生気分なのか

Claude Codeで開発するならWSL2ファイルシステムに資材を置きたい

Claude Codeを使い始めると、めちゃくちゃコマンドラインツールを使うことに気づくでしょう。grep飛ばして、find回して、sedで置換して。まるでコマンドラインの忍者です。

ぼくは業務上Windowsを使っているわけですが、そうすると「あー、WSL2入れとくか」となるわけです。UNIX系ツールが揃ってるしDockerも動くし完璧。Microsoftはえらい。

ところがです。他の人から「npm install遅くない?」って言われる。 原因が何か。Windows側にプロジェクト置いているんです。/mnt/c/Users/...配下に。この構成は遅くなる。

WSL2って、実は軽量VMなんです。WindowsとLinuxの間には、ちゃんと境界線が引かれています。その境界を越えてファイルアクセスするたびに、9Pっていうプロトコルが介在します。これが、思った以上に重い。

一応、公式の推奨は「WSL2使っていてもOS間を跨いでファイルアクセスすんな」です。

We recommend against working across operating systems with your files, unless you have a specific reason for doing so. For the fastest performance speed, store your files in the WSL file system if you are working in a Linux command line (Ubuntu, OpenSUSE, etc). If you're working in a Windows command line (PowerShell, Command Prompt), store your files in the Windows file system.

(意訳)ファイルを扱う際、特別な理由がない限り、オペレーティングシステムをまたいで作業することは推奨しません。最速のパフォーマンスを得るには、Linuxコマンドライン(Ubuntu、OpenSUSEなど)で作業している場合はWSLファイルシステムにファイルを保存し、Windowsコマンドライン(PowerShell、コマンドプロンプト)で作業している場合はWindowsファイルシステムにファイルを保存してください。

Working across file systems | Microsoft Learn

AIエージェントはコマンドラインの魔法使い

Claude Codeを眺めていると、コマンドが飛び交います。grep、sed、find、awk。数十年磨かれてきたUNIXツールの饗宴です。

こいつらの真価は、パイプラインで繋いだときに出ます。標準入力を受け取って、加工して、標準出力に流す。この単純な思想が、複雑な処理をエレガントに組み立てる基盤になってる。

# Claude Codeが実行するような典型的なコマンド例
grep -r "export function" src/ | wc -l
find . -name "*.test.ts" -exec grep -l "describe" {} \;

「PowerShellでも同じことできるじゃん」と言われると、たしかにできる。違うのはエコシステムの厚みなのかなと思います。npmパッケージも、Dockerイメージも、CI/CDパイプラインも、Linuxとの親和性が強い。

AIエージェントは、コマンドラインの魔法使いです。魔法の杖が揃ってる環境じゃないと、本領発揮できません。だからWSL2なんだと思っております。

WSL2は軽量VMという名の別マシン

雑にいうと「WSL2って、Windows上でLinux動かすやつです」なんですが、その正体はHyper-Vベースの軽量VM(Utility VM)です。その中で、本物のLinuxカーネルが動いてます。本物です。エミュレーションじゃない。

WSL1のときは違いました。あれはシステムコール翻訳レイヤーでした。Linuxのシステムコールを受け取って、「これWindowsだとこうですね」ってNT APIに翻訳してた。通訳みたいなもんです。だから一部のシステムコールが未実装で、Dockerとか動かなかった。

WSL2は方針転換しました。「通訳やめた。本物のLinuxカーネル入れる」と。おかげでDockerも動くし、systemdも動く。互換性は格段に上がりました。

だけど、軽量だからって、VMでなくなったわけではない。ダイエットコーラがコーラなのと同じ。起動が速い、リソース消費が少ない。でも、Windows⇔Linux間には明確な壁があります。ネットワークスタックは別、ファイルシステムは別、プロセス空間も別。

つまり、WSL2は「別マシン」です。このイメージを持っておくと、色々腑に落ちます。

diagram

Windows⇔Linuxの壁を越えるコストが重い

WSL2のファイルシステムは二重構造です。Linux側はext4(VHDXファイルに格納)、Windows側はNTFS。それぞれ独立してます。

で、相互アクセスできます。Linux側から/mnt/cでWindowsのCドライブが見えるし、Windows側から\\wsl$\UbuntuでLinux側が見える。便利じゃないですか。

だけど、この相互アクセスには代償があります。

代償の正体が、9P(Plan 9 Filesystem Protocol)。Plan 9っていう伝説の分散OS由来のプロトコルです。ネットワーク越しのファイルアクセスを想定して作られてます。そう、ネットワーク越し。

WSL2では、この9Pを使ってWindows⇔Linux間のファイル操作をやってます。通信経路はVSock(VMとホスト間の仮想ソケット)なので、物理的なネットワークは経由しません。たぶん。でも、プロトコル自体はネットワーク前提の設計なんです。

まず、VM境界を越える。これだけでコストです。ローカルファイルシステムならカーネル内で一瞬で終わる操作が、VMを越えて通信しなきゃいけない。

次に、プロトコル変換のオーバーヘッド。Linuxの1回のシステムコール(たとえばopen())が、9Pでは複数回のメッセージ往復に化けます。Twalk(パス探索)、Topen(開く)、Tread(読む)、Tclunk(閉じる)。1回で済むはずが、何往復もするんです。

そして、メタデータアクセスが特に遅い。stat()でファイル属性取るだけでも、往復が発生します。git statusfindみたいに大量のファイルを調べる操作は、この往復が積み重なって「あれ?固まった?」ってなります。

対照的に、Linux側で完結する操作は爆速です。ネイティブext4の速度。VM境界を越えないから。

9Pは自体が悪いわけではないんですが。数千個のnode_modulesを相手にするには、ちょっと荷が重い。

# Linux側(速い)
time find /home/user/project/node_modules -ls | wc -l

# Windows側経由(遅い)
time find /mnt/c/Users/user/project/node_modules -ls | wc -l

diagram

node_modulesは9Pの天敵

ビルドシステムやパッケージマネージャは、ファイルシステムにとってのストレステストです。容赦ない。

フロントエンド開発でnpm install。node_modulesに数万個のファイルが降ってきます。Rustでcargo build。依存関係解決のために、大量のメタデータアクセスが飛びます。

これらの操作、やたらとメタデータアクセスします。ファイル存在確認、属性読み取り、ディレクトリ走査。9Pプロトコルでは、これが全部メッセージ往復に化けます。各ファイルごとに、です。

上記エントリでは、Windows側に置いたNode.jsプロジェクトでyarn buildしたベンチマークが語られていますが。WSL2 Nativeで実施した場合に対して10倍の時間がかかっています。10倍です。10倍。コーヒー淹れに行くか、PCの前で待つか。この差は大きい。

# Windows側に配置した場合(悪い例)
/mnt/c/Users/username/project/  # ❌ 遅い

# WSL2側に配置した場合(良い例)
/home/username/project/  # ✅ 速い

じゃあどこに置けばいいのか

答えはシンプルで、WSL2上のファイルシステム(/home以下)に置こう。

I/Oが頻繁に発生するプロジェクトは、Linux側で完結させる。これが原則。Gitリポジトリ、ソースコード、ビルド成果物、依存関係(node_modules、target、venv等)。全部Linux側。VM境界を越えない。ネイティブext4の速度で処理される。

「でもExcelで開くドキュメントとかあるし」。それはWindows側でいいと思います。開発の中心はLinux側。だけど、Windows側からアクセスする手段もあります。エクスプローラーで\\wsl$\Ubuntu\home\username\projectsって打てば、Linux側のファイルが見えます。\\wsl$というワープゲート。魔法みたいですが、公式機能だし。

さらに言うと、VS Code Remote WSL拡張が完璧です。エディタはWindows側で快適に動かしながら、ファイルとプロセスはLinux側で扱う。ハイブリッド構成。エディタの快適さとI/O性能、両取りできます。

# WSL2上での開発ディレクトリ作成
mkdir -p ~/projects/myapp
cd ~/projects/myapp
git clone https://github.com/user/repo.git .
npm install  # 高速!
# WindowsからWSL2ファイルへアクセス
explorer.exe \\wsl$\Ubuntu\home\username\projects\myapp

まとめ

AIエージェント時代、WSL2は必須環境です。UNIX系ツールが揃ってるし、Dockerも動く。最高じゃないですか。

だけど、ファイル配置場所を間違えると、地獄を見ます。npm installで5分待つ、みたいな。

WSL2は軽量VMです。別マシンです。Windows⇔Linux間には壁があって、その壁を越えるたびに9Pプロトコルが介在します。1回のシステムコールが複数回のメッセージ往復に化けて、累積レイテンシが無視できないレベルになる。特にnode_modules。

解決策はシンプル。開発資材はWSL2上のファイルシステム(/home以下)に置く。Linux側で完結させる。これだけで爆速です。

Windows側からアクセスしたい?\\wsl$経由で見られます。VS Code Remote WSL使えば、エディタの快適さとI/O性能、両取りできます。

「別マシン」って考えれば、迷いません。Linuxで開発するなら、Linux側に資材を置こう。