PyPy: เร็วขึ้น 5 เท่า แต่บางทีก็เจอรักขม
สวัสดีครับทุกคน! วันนี้มาคุยเรื่อง Python ที่หลายคนอาจจะเคยได้ยินแต่ไม่เคยลองใช้จริงจัง นั่นก็คือ PyPy นั่นเอง
PyPy คืออะไร ทำไมต้องสน?
PyPy มันคือ Python Interpreter อีกตัวนะ ไม่ใช่แค่รันไทม์ปกติที่มาจาก CPython ที่เราใช้กันประจำๆ แต่มันมีของดีคือ JIT Compiler (Just-In-Time Compiler) ทำให้โค้ดของเรามันรันได้เร็วจี๋เลย บางเคสคือเห็นผลชัดเจนมาก 3-5 เท่าก็มีให้เห็นเยอะแยะเลยแหละ
ลองคิดดูดิ ถ้าโปรเจกต์คุณมัน CPU-bound แล้วโค้ดไม่ได้ไปเรียกอะไรแปลกๆ เยอะ การเปลี่ยนมารันกับ PyPy มันเหมือนได้อัปเกรดเครื่องฟรีๆ เลยนะ โคตรคุ้ม!
เริ่มใช้ PyPy ยังไงดี?
การลง PyPy มันไม่เหมือนลงไลบรารีปกติใน Python นะ มันคือ Interpreter เลย เวลาใช้ก็ต้องดาวน์โหลดมาติดตั้งแยกต่างหาก อย่างผมชอบใช้ pyenv ก็จะประมาณนี้
pyenv install pypy3.10-7.3.13 # เลือกเวอร์ชั่นที่ต้องการ
pyenv global pypy3.10-7.3.13 # ถ้าอยากให้เป็น default เลย (ระวัง!)
หรือถ้าอยากลองใช้แค่ในโปรเจกต์นั้นๆ ก็ใช้ pyenv local เอา
ลองเช็คดู python --version หรือ pypy --version ถ้าเจอ PyPy ก็คือใช้ได้แล้ว
มาลองดูกันว่ามันเร็วจริงไหม?
ลองเขียนโค้ดง่ายๆ มาเปรียบเทียบความเร็วกันดีกว่า
# test_speed.py
import time
def factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)
start_time = time.time()
for _ in range(10000): # ลองวนซักหมื่นรอบ
factorial(50)
end_time = time.time()
print(f"ใช้เวลาไป: {end_time - start_time:.4f} วินาที")
แล้วลองรันด้วย CPython ปกติ
python test_speed.py
# ตัวอย่างผลลัพธ์: ใช้เวลาไป: 0.2875 วินาที
ทีนี้มารันด้วย PyPy (ถ้าคุณตั้งค่า pyenv หรือ path ไว้ดีแล้ว)
pypy test_speed.py
# ตัวอย่างผลลัพธ์: ใช้เวลาไป: 0.0521 วินาที
คุณจะเห็นเลยว่า PyPy มันเร็วกว่าเยอะมากกกกกก! สำหรับโค้ดแบบนี้ที่ไม่มี I/O เยอะๆ หรือเรียก C extension ที่ซับซ้อน มันคือเทพเลยครับ
The "รักขม" ของ PyPy
แต่ชีวิตมันไม่ได้ง่ายขนาดนั้นไง! PyPy มันมีจุดอ่อนที่โคตรน่าหงุดหงิดเลย นั่นก็คือเรื่องของ C Extensions
คือเวลาที่เราใช้ไลบรารีที่เขียนด้วย C/C++ แล้วมีส่วนที่คอมไพล์มาเป็น .so หรือ .dll ไฟล์เนี่ย บางที PyPy มันไม่เข้าใจ หรือไม่สามารถ JIT คอมไพล์ส่วนนั้นได้ดีเท่า CPython
ยกตัวอย่างง่ายๆ เลย พวก numpy, pandas, หรือแม้กระทั่ง cryptography บางเวอร์ชั่น ถ้าไปใช้กับ PyPy ตรงๆ อาจจะเจอปัญหาได้เลยนะ
ตัวอย่าง Error ที่เคยเจอ:
เคยเจอมั้ยล่ะ เวลาจะลง cryptography ใน PyPy แล้วมันฟ้องแบบนี้...
Collecting cryptography
Downloading cryptography-3.4.8.tar.gz (547 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 547.7/547.7 kB 4.3 MB/s eta 0:00:00
Installing build dependencies ... error
error: subprocess-exited-with-error
× pip subprocess to install build dependencies did not run successfully.
│ exit code: 1
╰─> [24 lines of output]
# ... (truncated for brevity) ...
# บางทีมันจะฟ้องเกี่ยวกับ `rust` หรือ `cffi` หรือ `setuptools_rust` อะไรทำนองนี้
# คือมันพยายามจะคอมไพล์ C extension แต่ PyPy มันงอแงไม่ยอมให้ผ่าน
# หรือบางทีก็เป็นเรื่องของ ABI (Application Binary Interface) mismatch
# ทำให้ใช้ไลบรารีที่ pre-compiled มากับ CPython ไม่ได้
Could not build wheels for cryptography, which is required to install pyproject.toml-based projects
[end of output]
note: This error originates from a subprocess, and is not an issue with pip.
error: subprocess-exited-with-error
× pip subprocess to install build dependencies did not run successfully.
│ exit code: 1
╰─> See above for output.
note: This error originates from a subprocess, and is not an issue with pip.
เจอแบบนี้ก็ปวดหัวดิ! บางทีเราก็อยากได้ความเร็ว แต่ก็ต้องแลกกับความเข้ากันได้ของไลบรารีที่เราใช้ คือบางโปรเจกต์มันใช้ numpy หรือ pandas เป็นหลักอะ จะไปใช้ PyPy ก็ต้องคิดหนักมากๆ เลยนะ หรือไม่ก็ต้องหาไลบรารีอื่นที่ไม่มี C extension มาแทน ซึ่งบางทีมันก็เป็นไปไม่ได้ไง
ดังนั้น เวลาจะใช้ PyPy ให้คิดดีๆ ก่อนว่าโปรเจกต์เรามี dependency อะไรที่ต้องพึ่ง C extension เยอะมั้ย ถ้าไม่เยอะ หรือเป็นโค้ด Python เพียวๆ เลย อันนี้ PyPy คือพระเอกแน่นอน แต่ถ้ามีพวกนี้เยอะๆ ก็ต้องทำใจ หรือไม่ก็ลองหาเวอร์ชั่นของไลบรารีที่ PyPy มันรองรับดีๆ (ซึ่งอาจจะต้องใช้เวอร์ชั่นเก่ามากๆ) บอกเลยว่าชีวิตนักพัฒนาไม่เคยง่าย!
สรุป
สรุปคือ PyPy มันเป็นของดีจริงๆ ในแง่ของ performance แต่ก็มีข้อจำกัดเรื่อง C extensions ที่ต้องระวัง ถ้าโปรเจกต์คุณเหมาะกับมัน คือไม่ได้ใช้ไลบรารีพวกนั้นเยอะ ลองใช้ดูครับ คุณจะทึ่งในความเร็วของมัน แต่ถ้าไม่... ก็กลับมาใช้ CPython เหมือนเดิมก็ได้ ไม่ได้เสียหายอะไร! เลือกใช้ให้ถูกกับงานนะครับ
หวังว่าบทความนี้จะเป็นประโยชน์สำหรับคนที่อยากลองอะไรใหม่ๆ กับ Python นะครับ เจอกันบทความหน้า!