Python実行速度をWindows / WSL2で測ってみたらかなり違った

結論からいうと、
― **Python を動かすならWSL,
というかLinux** ―
---


## :dolphin: 目的
大学で先輩の研究を手伝うことになり、かなり時間のかかるPythonでのシミュレーションを実行する機会がありました。
そこで、「Linuxで動かしたほうが速いのでは？」と提案して試してみたところ、体感で明らかに速いと感じました。
**本当に差があるのか**、しっかり検証してみることにしました。


## :wrench: 検証環境 & 手順
以下の環境で、同じコードを動かし検証します
|  | Windows | WSL2 (Ubuntu) | Ubuntu24.04 LTS |
|----------|------------|---------------------|--------------------------|
| OS | Windows 11 | Linux 6.6.87.1-microsoft-standard-WSL2 | Linux 6.11.0-26-generic |
| OSバージョン | 10.0.26100 | #1 SMP PREEMPT_DYNAMIC Mon Apr 21        | #26~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Apr 17 19:20:47 UTC 2                    |
| アーキテクチャ   | AMD64     | x86_64              | x86_64                   |
| Python | 3.13.3 | 3.12.3 | 3.12.3 |
| プロセッサ      | Intel64 Family 6 Model 158 Stepping 9, GenuineIntel | x86_64 | x86_64 |

またハードウェアは
CPU： **intel Core i5-7500**
メモリ： **DDR4 32GB**
ディスク：SSDですが、WindowsはNVMe, UbuntuはSATAで分離しています

## :whale2: 検証内容
３つの処理の時間を計測します。
（本当ならもっと"速度変化のある処理"があるはずですが、適当で簡単に気になるところだけを検証していきます。）
1. シンプルな**繰り返し処理**
2. **モジュール(Numpy)を用いた複雑数値計算**、
3. **ファイルの入出力処理**

<details><summary> 検証コード </summary>

```Python
import os
import time
import platform
import numpy as np

print(f"OS: {platform.system()} {platform.release()}")
print(f"OSバージョン: {platform.version()}")
print(f"アーキテクチャ: {platform.machine()}")
print(f"Pythonバージョン: {platform.python_version()}")
print(f"プロセッサ: {platform.processor()}")

print()

# k回の平均を結果として出力する
k = 10
repetitions_result = [0] * k
numpydot_result = [0] * k
fileIO_result = [0] * k

for rep_i in range(k):
    print("1. for文の時間計測 - 0からnまで変化するiの2乗を計算")
    n = 1000000
    print(f"    繰り返し回数：n={n}")
    start = time.perf_counter()
    for i in range(n):
        if i % 2 == 0:
            _ = i * i
        else:
            _ = i * i * i
    end = time.perf_counter()
    print(f"    処理時間：{end - start:.6f}秒")
    repetitions_result[rep_i] = end - start

    print()
    print("2. Numpyによる行列計算 - n*nのランダムな行列を2つ生成し、行列の積を計算")
    n = 5000
    A = np.random.rand(n, n)
    B = np.random.rand(n, n)
    start = time.perf_counter()
    _ = np.dot(A, B)
    end = time.perf_counter()
    print(f"    処理時間：{end - start:.6f} 秒")
    numpydot_result[rep_i] = end - start

    print()
    print("3. I/O処理の時間計測 - n回ファイルを読み書き")
    n = 10000
    print(f"    繰り返し回数：n={n}")
    start = time.perf_counter()
    os.makedirs("tests", exist_ok=True)
    for i in range(n):
        with open(f"tests/test{i}.txt", "w") as f:
            f.write(f"test{i}\n")
        with open(f"tests/test{i}.txt", "r") as f:
            _ = f.read()
    end = time.perf_counter()
    print(f"    処理時間：{end - start:.6f}秒")
    fileIO_result[rep_i] = end - start

print()
print("10回の平均：")
print(f"    for文の平均時間：{sum(repetitions_result) / k:.6f}秒")
print(f"    Numpyによる行列計算の平均時間：{sum(numpydot_result) / k:.6f}秒")
print(f"    I/O処理の平均時間：{sum(fileIO_result) / k:.6f}秒")
```
</details>

---
## :bar_chart: 検証結果

| ベンチ項目 (平均値) | Windows | WSL2 (Ubuntu) | Ubuntu24.04 LTS |
|--------------------|---------|---------|--------------------|
| for ループ (1e6 回) | 0.233145 s | 0.220396 s |  **0.157500 s** |
| NumPy 行列積 (5k×5k) | 3.459947 s | 2.918494 s | **2.834514 s** |
| ファイル I/O (1万回) | 65.707492 s | 1.661 s | **0.664955 s** |

やはり、**Linuxのほうが全体的に速い**ですね。

forループの繰り返し処理とNumpyの処理は概ね同じような時間ですが、
**ファイルの読み書きが伴う処理**に関しては**Windows**が露骨に遅くなっています。

Pythonのバージョンによる差異があるかもしれませんが、おおむね3.13のほうが性能が向上しているらしいので、より顕著に表れているといえるでしょう。

## :fishing_pole_and_fish: まとめ：WSL使え！
不思議ですよね。直感でいうとWSLはWindowsの仮想環境だからWindowsよりはせいぜい同じくらいだと思いますよね。
WSL1はWindows上のエミュレーション程度だったらしいのですが、WSL2ではHyper-Vなどの技術で完璧なサブマシンみたいな動作ができるようになったようです。
とはいうものの、GUI処理(tkinter等)がある場合WSLでは余計にめんどくっさいこともあるので、目的に応じてですね。

ただ**処理速度ではWSLが断然いいとわかりました。**
VSCodeを使ってるならリモートからWSLに接続もできるので、基本開発するときはWSLのほうがいいでしょうね。

---
## :whale: メモ：なぜこんな差ができるのか？

1. **ファイルシステムの性能差**
   WindowsはNTFS、Linuxはext4でディスクがマウントされています。
   NTFSはWindows特有すぎて、堅牢でセキュリティなどに強いですが速さを求めるI/O処理には適していないんですかね。
   
2. **:exclamation: （たぶん元凶）Windowsシステム関係ソフトが介入**
   ファイルシステムだけでなく、Windows DefenderなどのWindowsシステムアプリが遅くすることもあるようです。
   ちいさなファイルが1つでもできるたびにDefenderがチェックしていくため、余計に遅くなるんでしょう。
   WSL2では仮想ディスク上のext4ファイルシステム(.vhdx)を使用しており、独立して動くそうです。
   むしろ、WSLで動かしてもWindowsのCドライブ上に保存するようだと効果がなく、遅くなるものだと思われます。

3. **I/Oシステムコールの軽さ**
   Linuxはファイル操作（open / read / write / close など）のシステムコールが軽量に設計されています。
   Windowsでは内部的にAPI層が深く、仮想ファイルレイヤーやセキュリティの抽象層を何段階も通るため、オーバーヘッドが多くなります。

4. **I/Oキャッシュ**
   WSL2では仮想的なLinuxカーネル上で処理が行われるため、Linux本来のファイルキャッシュ／書き込みバッファリング機構が効きます。

## 番外メモ：aptとpip
ubuntuにて、この検証のためPythonのnumpyを入れるときapt経由か、pip経由の2通りありました。
そもそも環境を立てたことないubuntuの環境だとpipすら入ってなかったので、apt経由で入れたところ、
`Numpyによる行列計算の平均時間：87.665445秒`
となり、**非常に、異常に遅くなりました**。
windowsでも3秒くらいで処理できたのに、なぜ？？

どうやら、apt経由では最小限の構成でしかインストールされず非常に遅くなる。というか高速化するためのライブラリが何も入らないため、かなり遅くなるらしいです。

pip経由だと、高速化するためのBLASモジュール(C拡張バイナリ)としてOpenBLASが組み込まれていて、これがSIMD(Single-Instruction, MultipleData)を使うようにビルドされており、より高速化されるそうです。

---

...というのも、pipがubuntuにプリインストールされてないし、仮想環境を作らずにpipを使おうとすると最近怒られるようになったのでaptで入れたんですけど、結局使い物になりませんでした。違いを知ることができてよかったです。