นักพัฒนา Python ถกเถียงเรื่อง Virtual Threads เป็นทางเลือกแทนความซับซ้อนของ Async/Await

ทีมชุมชน BigGo
นักพัฒนา Python ถกเถียงเรื่อง Virtual Threads เป็นทางเลือกแทนความซับซ้อนของ Async/Await

ชุมชน Python กำลังหารือกันอย่างกระตือรือร้นเกี่ยวกับการเปลี่ยนแปลงที่อาจเกิดขึ้นจากรูปแบบ async/await ไปสู่ virtual threads เนื่องจากความหงุดหงิดที่เพิ่มขึ้นต่อความซับซ้อนของโมเดลการทำงานพร้อมกันในปัจจุบัน การถกเถียงครั้งนี้เน้นย้ำถึงคำถามพื้นฐานเกี่ยวกับวิธีที่ Python ควรจัดการกับการเขียนโปรแกรมแบบ concurrent ในอนาคต

ปัญหา Function Coloring

หนึ่งในประเด็นสำคัญที่ขับเคลื่อนการอภิปรายครั้งนี้คือสิ่งที่นักพัฒนาเรียกว่า function coloring ซึ่งเป็นข้อกำหนดที่ต้องมาร์กฟังก์ชันเป็น async และใช้คีย์เวิร์ด await ทั่วทั้งโค้ดเบส สิ่งนี้สร้างการแยกระหว่างโค้ดแบบ synchronous และ asynchronous ที่ไม่สามารถทำงานร่วมกันได้อย่างง่ายดาย นักพัฒนาหลายคนเปรียบเทียบสิ่งนี้กับ aspect-oriented programming จากยุค 1990 โดยแนะนำว่ามันเพิ่มความซับซ้อนของคอมไพเลอร์โดยไม่ได้ให้ประโยชน์ที่สมส่วน

ชุมชนได้สังเกตว่า async/await ทำให้คนจำนวนมากได้สัมผัสกับแนวคิดการเขียนโปรแกรมแบบ concurrent แต่ต้องแลกมาด้วยการต้องใช้เครื่องจักรภายในที่ซับซ้อนซึ่งรั่วไหลเข้าสู่โค้ดของผู้ใช้ ความซับซ้อนนี้กลายเป็นปัญหามากยิ่งขึ้นด้วยการเปลี่ยนแปลง free-threading ล่าสุดของ Python ซึ่งนำเสนอข้อกังวลเรื่อง threading ควบคู่ไปกับความซับซ้อนของ async

คำศัพท์เทคนิคสำคัญ

  • Function Coloring: ข้อกำหนดในการทำเครื่องหมายฟังก์ชันเป็น async/await ซึ่งสร้างเส้นทางโค้ด sync/async ที่เข้ากันไม่ได้
  • Structured Concurrency: รูปแบบการเขียนโปรแกรมที่ task ลูกไม่สามารถมีอายุการใช้งานยาวกว่า task แม่ได้
  • Virtual Threads: เธรดที่มีน้ำหนักเบาซึ่งจัดการโดย runtime แทนที่จะเป็นระบบปฏิบัติการ
  • Stackful vs Stackless Coroutines: วิธีการที่แตกต่างกันในการบันทึกสถานะการทำงานระหว่างการสลับ task
  • Free-threading: ฟีเจอร์ล่าสุดของ Python ที่ช่วยให้สามารถทำงานแบบขนานได้อย่างแท้จริงโดยไม่ต้องใช้ Global Interpreter Lock (GIL)

Virtual Threads เป็นทางเลือกที่ง่ายกว่า

Virtual threads ซึ่งคล้ายกับ goroutines ของ Go หรือ Project Loom ของ Java นำเสนอแนวทางที่แตกต่าง แทนที่จะต้องใช้ syntax พิเศษ พวกมันจะอนุญาตให้มีการเรียกฟังก์ชันแบบ blocking ปกติในขณะที่ runtime จัดการการจัดตารางเวลาเบื้องหลัง นี่หมายความว่านักพัฒนาสามารถเขียนโค้ดที่ดูง่ายและเป็นลำดับแต่จริงๆ แล้วทำงานแบบ concurrent

โมเดลที่เสนอจะใช้ structured concurrency ผ่าน thread groups เพื่อให้แน่ใจว่า child threads จะไม่มีอายุยืนกว่า parents ของพวกมัน ความสัมพันธ์นี้ทำให้การไหลของข้อมูลชัดเจนกว่าตัวแปร thread-local แบบดั้งเดิม อย่างไรก็ตาม การนำไปใช้ใน Python เผชิญกับความท้าทายเนื่องจากกฎการกำหนดขอบเขตของภาษาและการขาด variable declarations

การพิจารณาด้านประสิทธิภาพและหน่วยความจำ

นักวิจารณ์ชี้ไปที่งานวิจัยที่แนะนำว่า stackless coroutines (โมเดล async/await ปัจจุบัน) มีประสิทธิภาพหน่วยความจำมากกว่าและมีต้นทุนการสลับต่ำกว่าทางเลือกแบบ stackful เช่น virtual threads อย่างไรก็ตาม สมาชิกชุมชนโต้แย้งว่าความแตกต่างด้านประสิทธิภาพเหล่านี้มีความสำคัญเล็กน้อยในบริบทของ Python ที่ overhead ของ interpreter มีอิทธิพลเหนือกว่า

จริงๆ แล้วไม่มีเหตุผลเลยที่ python จะต้องเลือกโมเดล async/await

การถกเถียงขยายไปเกินประสิทธิภาพล้วนๆ ไปสู่ผลิตภาพของนักพัฒนา บางคนโต้แย้งว่าโซลูชันที่ง่ายกว่าแม้จะไม่เหมาะสมที่สุดก็สามารถเร็วกว่าในเวลาพัฒนารวม แม้ว่าจะช้ากว่าใน runtime

การเปรียบเทียบโมเดลการทำงานพร้อมกัน

แนวทาง ความซับซ้อนของ Syntax การใช้หน่วยความจำ ประสบการณ์ Developer ประสิทธิภาพ
Async/Await สูง (function coloring) ต่ำ ซับซ้อน ปรับให้เหมาะสม
Virtual Threads ต่ำ (ฟังก์ชันปกติ) ปานกลาง ง่าย ดีพอ
Gevent ต่ำ (monkey patching) ปานกลาง ง่าย ดี
Traditional Threads ต่ำ สูง ซับซ้อน (locks) แปรผัน

ความท้าทายของไลบรารีในโลกจริง

การอภิปรายเผยให้เห็นปัญหาเชิงปฏิบัติกับไลบรารี async ปัจจุบัน ปัญหาการจัดการ cancellation ในไลบรารียอดนิยมเช่นที่จัดการ file I/O สามารถทำให้เกิด deadlocks เมื่อใช้กับรูปแบบ structured concurrency ปัญหาเหล่านี้เกิดจากการผสมโค้ด async กับ thread pools ทำให้เกิดสถานการณ์ที่ cancellation ที่เหมาะสมกลายเป็นไปไม่ได้

แนวทางทางเลือกที่ได้รับความสนใจ

นักพัฒนาหลายคนกล่าวถึงประสบการณ์ที่ประสบความสำเร็จกับ gevent ซึ่งใช้ monkey patching เพื่อให้ cooperative multitasking โดยไม่มี function coloring คนอื่นๆ ชี้ไปที่ภาษาเช่น Elixir เป็นตัวอย่างของโมเดลการทำงานพร้อมกันที่ง่ายกว่าซึ่งหลีกเลี่ยงความซับซ้อนเหล่านี้ทั้งหมด

แนวทางของระบบนิเวศ Rust ก็ถูกกล่าวถึงเช่นกัน ที่นักพัฒนาสามารถเลือกระหว่างโมเดลการทำงานพร้อมกันที่แตกต่างกันแทนที่จะถูกล็อกเข้าสู่แนวทางเดียว ความยืดหยุ่นนี้ช่วยให้โปรเจ็กต์สามารถเลือกเครื่องมือที่ดีที่สุดสำหรับความต้องการเฉพาะของพวกเขา

มองไปข้างหน้า

แม้ว่า virtual threads จะยังไม่ได้รับการวางแผนอย่างเป็นทางการสำหรับ Python แต่การอภิปรายสะท้อนถึงความไม่พอใจในวงกว้างต่อรูปแบบ async ปัจจุบัน ชุมชนดูเหมือนจะแบ่งออกเป็นสองฝ่าย ระหว่างผู้ที่ต้องการผลักดันการปรับปรุง async/await และผู้ที่สนับสนุนการเปลี่ยนแปลงพื้นฐานไปสู่การทำงานพร้อมกันแบบ thread-based

การถกเถียงในท้ายที่สุดมุ่งเน้นไปที่ว่า Python ควรให้ความสำคัญกับการเพิ่มประสิทธิภาพเชิงทฤษฎีหรือประสบการณ์ของนักพัฒนาและความเรียบง่ายของโค้ด เมื่อภาษาพัฒนาไปพร้อมกับฟีเจอร์เช่น free-threading การตัดสินใจด้านสถาปัตยกรรมเหล่านี้กลายเป็นสิ่งสำคัญมากขึ้นสำหรับทิศทางอนาคตของ Python

อ้างอิง: From Async/Await to Virtual Threads