ชุมชน 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