Python Fork ของ HRT ประสบความสำเร็จในการเพิ่มประสิทธิภาพผ่านการใช้งาน Lazy Import

ทีมชุมชน BigGo
Python Fork ของ HRT ประสบความสำเร็จในการเพิ่มประสิทธิภาพผ่านการใช้งาน Lazy Import

Hudson River Trading ( HRT ) ได้ประสบความสำเร็จในการนำ Python fork แบบกำหนดเองมาใช้งานทั่วทั้งองค์กร โดยการใช้งาน lazy imports เพื่อลดเวลาเริ่มต้นของแอปพลิเคชัน Python อย่างมาก ทีมวิศวกรรมของบริษัทเทรดดิ้งแห่งนี้ใช้เวลากว่าสองปีในการพัฒนาและย้ายไปใช้โซลูชันนี้ ซึ่งจะเลื่อนการโหลดโมดูลจนกว่าจะต้องใช้งานจริงในระหว่าง runtime

ปัญหาที่จุดประกายนวัตกรรม

สถาปัตยกรรม monorepo ของ HRT แม้จะช่วยให้ทีมต่างๆ สามารถทำงานร่วมกันได้ แต่กลับสร้างคอขวดด้านประสิทธิภาพที่สำคัญ สคริปต์ Python ของพวกเขากำลัง import โมดูลจำนวนมากมายตอนเริ่มต้น โดยที่หลายๆ imports ไม่เคยถูกใช้งานจริงระหว่างการทำงาน ส่งผลให้เครื่องมือ command-line ใช้เวลาหลายสิบวินาทีในการเริ่มต้น Jupyter notebooks ต้องใช้เวลาหลายนาทีในการโหลด และงาน distributed computing ใช้เวลาในการ import มากกว่าการคำนวณจริง ปัญหานี้รุนแรงเป็นพิเศษเพราะโมดูลของพวกเขามักอยู่ใน distributed file systems และมีโค้ดการเริ่มต้นที่หนัก

การอภิปรายในชุมชนเผยให้เห็นว่านี่ไม่ใช่ปัญหาเฉพาะของ HRT นักพัฒนาหลายคนต่อสู้กับปัญหา import overhead ของ Python โดยเฉพาะใน codebase ขนาดใหญ่ บางคนใช้วิธีแก้ปัญหาชั่วคราวด้วยตนเอง เช่น การวาง imports ไว้ในฟังก์ชันหรือใช้ lazy import libraries ที่มีอยู่ แต่แนวทางเหล่านี้สร้างความท้าทายในการบำรุงรักษาและทำให้โค้ดอ่านยากขึ้น

การปรับปรุงประสิทธิภาพ

  • เครื่องมือ command-line: ลดเวลาเริ่มต้นจากหลายสิบวินาทีเป็นเกือบทันที
  • Jupyter notebooks: กำจัดความล่าช้าในการ import ที่ใช้เวลา 10-15 นาที
  • งานแบบกระจาย: ลดเวลาที่ใช้ในการโหลด dependency ที่ไม่จำเป็นอย่างมีนัยสำคัญ
  • โดยรวม: ปรับปรุงเวลาเริ่มต้นได้ 3 เท่า (อิงจากการใช้งานที่คล้ายกัน)
กราฟแท่งเทียนที่แสดงการเคลื่อนไหวของราคา สะท้อนบริบททางการเงินที่ HRT ดำเนินงานอยู่และความสำคัญของการ import ที่มีประสิทธิภาพสำหรับกิจกรรมการเทรด
กราฟแท่งเทียนที่แสดงการเคลื่อนไหวของราคา สะท้อนบริบททางการเงินที่ HRT ดำเนินงานอยู่และความสำคัญของการ import ที่มีประสิทธิภาพสำหรับกิจกรรมการเทรด

การใช้งานทางเทคนิคและความท้าทาย

HRT ยืมแนวคิด lazy import จาก Cinder Python fork ของ Meta โดยใช้การปรับเปลี่ยน CPython สองส่วนหลัก แทนที่จะทำ imports ทันที interpreter จะสร้าง placeholder objects ที่เลื่อนการโหลดโมดูลจริงจนกว่าชื่อที่ import จะถูกอ้างอิง แนวทางนี้ทำงานแบบโปร่งใสสำหรับกรณีการใช้งานส่วนใหญ่ แต่มาพร้อมกับข้อจำกัดที่น่าสังเกต

การใช้งานนี้ไม่สามารถจัดการ imports ภายในฟังก์ชันได้เนื่องจากการปรับปรุง local variable ของ Python และ wildcard imports ยังคงเป็นไปไม่ได้ที่จะทำให้ lazy เพราะไม่สามารถกำหนดชื่อที่ export ได้โดยไม่ต้องประเมิน ที่สำคัญกว่านั้น โมดูลที่มี side effects - ที่ปรับเปลี่ยน global state ระหว่าง import - สามารถทำให้เกิดบั๊กที่ละเอียดอ่อนเมื่อการทำงานของพวกเขาถูกเลื่อน

Runtime imports เป็นฝันร้ายในการบำรุงรักษาและสามารถแยกส่วน codebase ได้อย่างรวดเร็ว การวิเคราะห์แบบคงที่ของ imports เป็นสิ่งที่ต้องการมากจนเกือบจะคุ้มค่ากับการสูญเสียประสิทธิภาพการเริ่มต้นเสมอ

ความคิดเห็นนี้เน้นความตึงเครียดหลักในแนวทาง ในขณะที่ lazy imports แก้ปัญหาประสิทธิภาพ แต่อาจทำให้พฤติกรรมของโค้ดคาดเดาได้น้อยลง

ข้อจำกัดทางเทคนิค

  • ไม่สามารถทำให้การ import เป็นแบบ lazy ภายในขอบเขตของฟังก์ชันได้
  • ไม่รองรับการ import แบบ wildcard (from module import *)
  • โมดูลที่มี side effects ต้องการการจัดการพิเศษ
  • การพึ่งพาลำดับของการ import อาจเสียหาย
  • การ import แบบ transitive โดยนัยต้องประกาศอย่างชัดเจน

ประสบการณ์การย้ายและบทเรียนที่ได้เรียนรู้

กระบวนการย้ายเผยให้เห็นปัญหาความเข้ากันได้สามประเภทหลัก Import side effects ทำให้เกิดความท้าทายในการดีบั๊กที่ยากที่สุด เนื่องจากการลงทะเบียน decorator และการกำหนดค่าส่วนกลางจะทำงานในเวลาที่ไม่คาดคิดหรือไม่ทำงานเลย การพึ่งพาลำดับ import กลายเป็นปัญหาเมื่อโมดูลที่มี side effects ขัดแย้งกันไม่ได้โหลดตามลำดับที่คาดเดาได้อีกต่อไป นอกจากนี้ implicit transitive imports - ที่โค้ดพึ่งพา submodules ที่ import โดยโมดูลอื่น - เสียหายเมื่อ dependencies เหล่านั้นไม่ได้โหลดจริง

HRT แก้ไขปัญหาเหล่านี้ผ่านการรวมกันของ eager import blocks, exclusion lists สำหรับ third-party packages และการจัดการ dependency แบบชัดเจน บริษัทได้เสร็จสิ้นการย้ายพร้อมกับการอัพเกรด Python 3.12 ทำให้ lazy imports เป็นค่าเริ่มต้นสำหรับโค้ด Python ทั้งหมดภายในไตรมาสที่ 2 ปี 2025

ไทม์ไลน์การย้ายระบบ

  • Q1 2023: พัฒนาต้นแบบเริ่มต้นระหว่างการแข่งขัน hackathon ภายในองค์กร
  • Q2-Q4 2023: ปรับปรุงการใช้งานและการย้ายทีมงานในช่วงแรก
  • Q2 2024: บรรลุความเข้ากันได้แบบ lazy 50% ทั่วทั้ง monorepo
  • Q3 2024: เสร็จสิ้นการย้ายไปยัง Python 3.12
  • Q2 2025: ปรับใช้ lazy imports เป็นค่าเริ่มต้นทั่วทั้งบริษัท

ผลกระทบต่อประสิทธิภาพและแนวโน้มในอนาคต

ผลลัพธ์ที่ได้มีความสำคัญทั่วระบบนิเวศ Python ของ HRT เครื่องมือ command-line ตอนนี้ให้ feedback ทันทีแทนที่จะมีความล่าช้าในการเริ่มต้นหลายนาที Jupyter notebook workflows ที่เคยต้องใช้เวลา import 10-15 นาทีตอนนี้เริ่มต้นได้เกือบทันที งาน Distributed computing ที่ใช้เวลาโหลด dependencies มากกว่าการทำงานจริงได้เห็นการปรับปรุงประสิทธิภาพอย่างมาก

แม้จะประสบความสำเร็จ HRT ยอมรับภาระการบำรุงรักษาของการดูแล Python fork พวกเขากำลังสำรวจการเสนอ explicit lazy import syntax ให้กับ upstream Python โดยใช้คำสำคัญเช่น lazy import foo แทนที่จะทำให้ laziness เป็นแบบ implicit แนวทางนี้จะแก้ไขความกังวลของ Python Steering Council เกี่ยวกับบั๊กที่ละเอียดอ่อนในขณะที่ทำให้ประโยชน์ด้านประสิทธิภาพพร้อมใช้งานสำหรับชุมชน Python ที่กว้างขึ้น

การอภิปรายรอบการใช้งานของ HRT สะท้อนคำถามที่กว้างขึ้นเกี่ยวกับลักษณะประสิทธิภาพของ Python และการแลกเปลี่ยนระหว่างความสะดวกและความเร็วในการพัฒนาซอฟต์แวร์ขนาดใหญ่

อ้างอิง: Inside HRT's Python Fork: Leveraging PEP 690 for Faster Imports