Python CLI เร็วขึ้นแบบงงๆ ด้วย JIT Compiler จัดการไฟล์สบาย
สวัสดีครับ,
ผมมีเรื่องน่าตื่นเต้นมาเล่าให้ฟังครับ โปรแกรมเมอร์อย่างเราๆ ที่ชอบเขียน Python CLI สำหรับงานจัดการไฟล์เอย ประมวลผลข้อมูลเอย บางทีมันก็รอนานใช่ไหมครับ ผมก็เป็นนะ เลยไปเจอวิธีที่ช่วยให้มันเร็วขึ้นแบบงงๆ เลย คือใช้ JIT Compiler เข้ามาช่วย นี่แหละครับ Numba ตัวเด็ดของเรา วันนี้ผมจะมาลองทำให้ดูว่ามันช่วยได้จริงๆ นะครับ
ลองคิดดูว่าเรามีไฟล์ข้อมูลใหญ่ๆ แล้วต้องมานั่ง loop อ่านทีละบรรทัด ประมวลผล แล้วเขียนออกไปใหม่ แค่คิดก็เหนื่อยแล้วครับ ผมลองยกตัวอย่างง่ายๆ ให้ดูนะครับ สมมติเรามีไฟล์ data.txt ที่มีตัวเลขเยอะๆ แล้วเราอยากจะคูณเลขแต่ละบรรทัดด้วย 2 แล้ว Save เป็น output.txt แบบนี้นะครับ
โค้ดแบบบ้านๆ ก่อน JIT (อาจจะช้า):
# slow_processor.py
def process_file_slow(input_file, output_file):
with open(input_file, 'r') as infile,
open(output_file, 'w') as outfile:
for line in infile:
try:
num = float(line.strip())
result = num * 2
outfile.write(f'{result}\
')
except ValueError:
# ถ้าไม่ใช่ตัวเลข ก็ข้ามไป
continue
if __name__ == '__main__':
# สร้างไฟล์สำหรับทดสอบ
with open('data.txt', 'w') as f:
for i in range(1_000_000):
f.write(f'{i}\
')
print('เริ่มประมวลผลแบบธรรมดา...')
import time
start_time = time.time()
process_file_slow('data.txt', 'output_slow.txt')
end_time = time.time()
print(f'ใช้เวลาไป: {end_time - start_time:.2f} วินาที')
จากนั้น ลองรันดูนะครับ ถ้าไฟล์ใหญ่ๆ นะ รอไปเลยครับ ส่วนตัวผมก็รอนานอยู่ครับ
ทีนี้เรามาลองใช้ Numba JIT Compiler เข้ามาช่วยดีกว่าครับ ก่อนอื่นต้องติดตั้ง Numba ก่อนนะ:
pip install numba
แล้วเราก็แค่เพิ่ม @jit เข้าไปใน function ที่เราอยากให้มันเร็วขึ้นครับ ง่ายมากๆ เลยครับ แบบนี้เลย:
โค้ดแบบมี Numba JIT (เร็วขึ้นเยอะ):
# fast_processor.py
from numba import jit
import numpy as np # Numba ชอบทำงานกับ numpy มากๆ ครับ
@jit(nopython=True) # nopython=True คือทำให้เร็วที่สุด ไม่ต้องกลับไป Python interpreter
def process_numbers_jit(numbers):
results = np.empty_like(numbers)
for i in range(len(numbers)):
results[i] = numbers[i] * 2
return results
def process_file_fast(input_file, output_file):
# อ่านข้อมูลทั้งหมดมาก่อน
with open(input_file, 'r') as infile:
# ใช้ list comprehension อ่านและกรองข้อมูล
lines = [float(line.strip()) for line in infile if line.strip().replace('.', '', 1).isdigit()]
numbers_array = np.array(lines, dtype=np.float64)
# เอาไปเข้าฟังก์ชันที่ JIT แล้ว
processed_numbers = process_numbers_jit(numbers_array)
with open(output_file, 'w') as outfile:
for num in processed_numbers:
outfile.write(f'{num}\
')
if __name__ == '__main__':
# สร้างไฟล์สำหรับทดสอบ (ใช้ไฟล์เดิม)
with open('data.txt', 'w') as f:
for i in range(1_000_000):
f.write(f'{i}\
')
print('เริ่มประมวลผลแบบ JIT...')
import time
start_time = time.time()
process_file_fast('data.txt', 'output_fast.txt')
end_time = time.time()
print(f'ใช้เวลาไป: {end_time - start_time:.2f} วินาที')
เห็นไหมครับ แค่เพิ่ม @jit เข้าไป แล้วก็ปรับให้มันทำงานกับ numpy array หน่อย (Numba ชอบมากๆ) มันก็วิ่งฉิวเลยครับ จริงๆ แล้ว Numba มันจะแปลงโค้ด Python ที่เราเขียน ไปเป็นโค้ดเครื่อง (Machine Code) ทำให้มันรันได้เร็วขึ้นเหมือนเขียนด้วย C/C++ เลยครับ แต่เรายังเขียน Python เหมือนเดิม
ข้อควรรู้เล็กน้อยสำหรับ Numba: - มันจะเวิร์คดีกับโค้ดที่เน้นการคำนวณตัวเลข ลูปเยอะๆ ครับ - ถ้าโค้ดเราไปยุ่งกับ Python objects เยอะๆ หรือ I/O เยอะๆ มันอาจจะไม่ได้เห็นผลมากเท่าที่ควรนะครับ - @jit(nopython=True) จะเร็วที่สุด แต่ก็เขียนยากกว่านิดหน่อย เพราะต้องระวังเรื่อง Python object ที่ไม่รองรับ
สุดท้ายนี้ ผมหวังว่าเทคนิคนี้จะช่วยให้เพื่อนๆ โปรแกรมเมอร์ สามารถทำให้ Python CLI ของเราที่ต้องทำงานหนักๆ กับไฟล์ มีประสิทธิภาพที่ดียิ่งขึ้นนะครับ ใครมีคำถาม หรืออยากแชร์เทคนิคอื่นๆ ก็คอมเมนต์กันเข้ามาได้เลยนะครับ สวัสดีครับ!
อ้างอิง: - Numba Documentation: https://numba.pydata.org/ - NumPy Documentation: https://numpy.org/ "