結論からいうと、
― Python を動かすならWSL,
というかLinux ―
目的
大学で先輩の研究を手伝うことになり、かなり時間のかかるPythonでのシミュレーションを実行する機会がありました。
そこで、「Linuxで動かしたほうが速いのでは?」と提案して試してみたところ、体感で明らかに速いと感じました。
本当に差があるのか、しっかり検証してみることにしました。
検証環境 & 手順
以下の環境で、同じコードを動かし検証します
| 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で分離しています
検証内容
3つの処理の時間を計測します。
(本当ならもっと"速度変化のある処理"があるはずですが、適当で簡単に気になるところだけを検証していきます。)
- シンプルな繰り返し処理
- モジュール(Numpy)を用いた複雑数値計算、
- ファイルの入出力処理
検証コード
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}秒")
検証結果
| ベンチ項目 (平均値) | 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のほうが性能が向上しているらしいので、より顕著に表れているといえるでしょう。
まとめ:WSL使え!
不思議ですよね。直感でいうとWSLはWindowsの仮想環境だからWindowsよりはせいぜい同じくらいだと思いますよね。
WSL1はWindows上のエミュレーション程度だったらしいのですが、WSL2ではHyper-Vなどの技術で完璧なサブマシンみたいな動作ができるようになったようです。
とはいうものの、GUI処理(tkinter等)がある場合WSLでは余計にめんどくっさいこともあるので、目的に応じてですね。
ただ処理速度ではWSLが断然いいとわかりました。
VSCodeを使ってるならリモートからWSLに接続もできるので、基本開発するときはWSLのほうがいいでしょうね。
メモ:なぜこんな差ができるのか?
-
ファイルシステムの性能差
WindowsはNTFS、Linuxはext4でディスクがマウントされています。
NTFSはWindows特有すぎて、堅牢でセキュリティなどに強いですが速さを求めるI/O処理には適していないんですかね。 -
(たぶん元凶)Windowsシステム関係ソフトが介入
ファイルシステムだけでなく、Windows DefenderなどのWindowsシステムアプリが遅くすることもあるようです。
ちいさなファイルが1つでもできるたびにDefenderがチェックしていくため、余計に遅くなるんでしょう。
WSL2では仮想ディスク上のext4ファイルシステム(.vhdx)を使用しており、独立して動くそうです。
むしろ、WSLで動かしてもWindowsのCドライブ上に保存するようだと効果がなく、遅くなるものだと思われます。 -
I/Oシステムコールの軽さ
Linuxはファイル操作(open / read / write / close など)のシステムコールが軽量に設計されています。
Windowsでは内部的にAPI層が深く、仮想ファイルレイヤーやセキュリティの抽象層を何段階も通るため、オーバーヘッドが多くなります。 -
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で入れたんですけど、結局使い物になりませんでした。違いを知ることができてよかったです。