แม้ Python จะมีข้อดีคือถูกใช้อย่างแพร่หลายในงาน AI, การวิเคราะห์ข้อมูล ฯลฯ และเขียนโค้ดได้รวดเร็ว แต่ปัญหาความช้าซึ่งเป็นเรื่องเรื้อรังของภาษาแบบ interpreter ก็อาจกลายเป็นเรื่องปวดหัวในการใช้งานจริงได้เช่นกัน

ในงานจริง เรามักพิจารณาทางเลือกหลายอย่างเพื่อปรับปรุงปัญหาความเร็วของ Python บางครั้งใช้โค้ด Python เฉพาะเป็นต้นแบบเริ่มต้น แล้วเมื่อย้ายไป production ก็พัฒนาขึ้นใหม่ด้วย Rust หรือ C/C++

ผมกำลังทดลองพัฒนาเครื่องมือชื่อ Rextio เพื่อเป็นทางเลือกใหม่ในการแก้ปัญหาความเร็ว โดยไม่ต้องทิ้ง Python

แนวคิดพื้นฐานคือ แปลงส่วนของโค้ด Python ที่สามารถแปลงเป็น native ได้ (เช่น โค้ดแบบ static ที่มี type hint) ให้เป็นโค้ด Rust โดยอัตโนมัติ แล้วคอมไพล์เป็นไบนารีเพื่อเพิ่มประสิทธิภาพ ส่วนที่แปลงเป็น native โดยอัตโนมัติได้ยาก (เช่น โค้ดแบบ dynamic) จะถูกคงไว้เป็นโค้ด Python ตามเดิม (fallback) และให้ CPython รัน เพื่อรักษา logic ของโค้ด Python ต้นฉบับไว้

ภาพรวมคร่าว ๆ เป็นดังนี้

โปรเจกต์ Python ที่ระบุชนิดข้อมูลไว้
-> วิเคราะห์ candidate ที่รองรับสำหรับ native
-> ปฏิเสธฟังก์ชันที่ไม่ปลอดภัยหรือยังไม่รองรับ
-> ฟังก์ชันที่ยอมรับจะสร้าง Rust + PyO3
-> ส่วนที่เหลือสร้าง Python fallback wrapper
-> สร้าง artifact ที่เข้ากันได้กับ import

รายละเอียดเพิ่มเติมโปรดดูเอกสารใน Git repository ตามลิงก์

เมื่อเปรียบเทียบการรันโดยรวม native binary ที่แปลงด้วย Rextio กับการรันโค้ด Python ต้นฉบับด้วย CPython จะเห็นการปรับปรุงด้านประสิทธิภาพเช่นกัน

  • เมื่อแปลงโค้ด Python พื้นฐานเป็น native แล้วรัน: 57.73×
  • เมื่อแปลง NumPy เป็น native แล้วรัน: 2.52×
  • เมื่อแปลง NetworkX เป็น native แล้วรันอัลกอริทึม Dijkstra: 3.68×
  • เมื่อแปลง Series.map ของ pandas เป็น native แล้วรัน: 66.14×
  • เมื่อแปลง PyTorch deep MLP เป็น native แล้วรัน: 1.02× (การเพิ่มความเร็วมีข้อจำกัด เพราะแพ็กเกจ Python เดิมใช้ C extension เป็นต้น)
  • เมื่อแปลง TensorFlow eager chain เป็น native แล้วรัน: 1.04× (การเพิ่มความเร็วมีข้อจำกัด เพราะแพ็กเกจ Python เดิมใช้ C extension เป็นต้น)

สำหรับซอร์สโค้ดและข้อมูลสภาพแวดล้อมการรันที่ใช้ใน benchmark ซึ่งให้ผลลัพธ์ข้างต้น โปรดดู rextio-benchmark Git repository

เพิ่มเติมคือ Rextio มี Core CLI สำหรับแปลงโค้ด Python และสั่งคอมไพล์ และกำลังพัฒนาให้สามารถสร้างและต่อปลั๊กอินเพิ่มเติมที่กำหนดกฎสำหรับแปลงแพ็กเกจ Python แต่ละตัวเป็นโค้ด Rust ได้ ปัจจุบันมีปลั๊กอินบางส่วน เช่น NumPy (rextio-numpy, rextio-networkx, rextio-pandas, rextio-torch, rextio-tensorflow เป็นต้น) และผล benchmark ข้างต้นเป็นผลจากการรันโดยใช้ปลั๊กอินเหล่านี้

แน่นอนว่า Rextio ยังเป็นโปรเจกต์ระยะเริ่มต้นที่ต้องปรับปรุงอีกมาก และการคอมไพล์โค้ด Python เป็น native ที่อิง Rust ไม่ได้ทำให้ประสิทธิภาพดีขึ้นในทุกสถานการณ์

ตัวอย่างเช่น หากมีการแลกเปลี่ยนข้อมูลระหว่างส่วน native กับส่วน CPython fallback บ่อย ๆ ข้อมูลต้องถูกแปลงและข้าม boundary จนอาจทำให้ช้าลงแทน อย่างไรก็ตาม ในกรณีเช่นนี้ Rextio พยายามชี้นำให้ fallback ส่วนนั้นทั้งหมดไปยัง CPython โดยไม่ผ่าน native เพื่อป้องกันความเร็วลดลง

หลังจากพัฒนาคนเดียวมาระยะหนึ่ง ตอนนี้รู้สึกว่าโปรเจกต์เริ่มเข้าที่พอสมควร จึงนำมาแนะนำที่นี่

หากมีคำถาม ความเห็น หรือ feedback ผมจะพยายามตอบและนำไปปรับปรุงให้มากที่สุด

ขอบคุณครับ

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น