2 คะแนน โดย GN⁺ 2023-09-09 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • บทความนี้กล่าวถึงความท้าทายของการใช้ Rust กับซอฟต์แวร์ userspace ที่มีการทำงานพร้อมกันในระดับขนาดใหญ่
  • โมเดลแบบอะซิงโครนัสของ Rust ถูกออกแบบมาเพื่อจัดการแนวคิดหลักสองประการของการประมวลผลสมัยใหม่ คือ concurrency และ parallelism
    • parallelism คือการรันโค้ดพร้อมกันบน CPU หลายตัว
    • concurrency คือการแยกปัญหาออกเป็นส่วนย่อยที่เป็นอิสระ และรันได้โดยไม่ขึ้นกับลำดับหรือมีเพียงลำดับบางส่วน
  • บทความนี้เน้นข้อจำกัดของการใช้หลายโปรเซสเพื่อรองรับ concurrency เนื่องจากการสื่อสารระหว่างโปรเซสมีต้นทุนสูง
  • เธรดซึ่งเป็นกระบวนการที่ใช้หน่วยความจำร่วมกัน ถูกเสนอเป็นทางเลือก แต่ก็อาจก่อให้เกิดปัญหาซับซ้อน เช่น race condition และ deadlock
  • งานวิจัยปี 1978 ของ Tony Hoare เรื่อง "Communicating Sequential Processes" เสนอให้ใช้คิวหรือแชนเนลเพื่อให้เธรดส่งข้อความหากัน ซึ่งให้ข้อดีหลายประการ เช่น การแยกตัวคล้ายโปรเซสและการดีบักที่ง่ายกว่า
  • ไลบรารีมาตรฐานของ Rust มีแชนเนลอยู่ภายใต้ std::sync::mpsc::sync_channel
  • อย่างไรก็ตาม สำหรับปัญหาที่ต้องการ concurrency ในระดับสูง เช่น เว็บเซิร์ฟเวอร์ที่เชื่อมต่อกับผู้ใช้นับหมื่น เธรดเพียงอย่างเดียวอาจไม่เพียงพอ
  • สำหรับสถานการณ์เช่นนี้ Rust ใช้โมเดล async/await ซึ่งเมื่อฟังก์ชันถูกทำเครื่องหมายว่าเป็นแบบอะซิงโครนัส จะคืนค่า future หรือ promise และสามารถรอเพื่อสร้างผลลัพธ์ได้
  • แม้จะมีข้อดี แต่ async Rust ก็มีความท้าทาย เช่น ความจำเป็นในการทำให้คอมไพเลอร์มั่นใจได้ว่าทุกอย่างจะทำงานได้ถูกต้อง ซึ่งอาจยากกว่าการใช้ raw threads
  • มีการเสนอให้ใช้ "atomic reference count" หรือ Arc เป็นทางออก แต่ก็ไม่ใช่ยาครอบจักรวาล เพราะอาจก่อให้เกิดปัญหาคล้ายกับที่พบใน garbage collector
  • บทความสรุปว่า แม้ Rust จะมีจุดแข็งในด้านอื่น ๆ แต่ก็อาจไม่ใช่เครื่องมือที่เหมาะที่สุดสำหรับซอฟต์แวร์ userspace ที่มีการทำงานพร้อมกันขนาดใหญ่

1 ความคิดเห็น

 
GN⁺ 2023-09-09
ความคิดเห็นจาก Hacker News
  • ผู้เขียนกำลังพัฒนาไคลเอนต์เมตาเวิร์สประสิทธิภาพสูงที่ต้องประมวลผลข้อมูลจำนวนมากแบบเรียลไทม์ด้วย Rust
  • โปรเจกต์ของผู้เขียนใช้หลายเธรดสำหรับงานหลากหลาย เช่น การเรนเดอร์กราฟิก การจัดการอีเวนต์เครือข่าย และการโหลดแอสเซ็ต
  • Rust มีประโยชน์ต่อโปรเจกต์นี้ และโดยปกติผู้เขียนเคยพบการแครชที่เกี่ยวกับหน่วยความจำปีละครั้งเพราะโค้ด "unsafe" ของคนอื่น
  • ผู้เขียนวิจารณ์ว่า Rust ไม่มี race condition แต่ไม่ได้แปลว่าไม่มี deadlock และเสนอว่าควรมีตัววิเคราะห์ deadlock แบบสแตติก
  • ผู้เขียนวิจารณ์การใช้งาน async อย่างแพร่หลายใน Rust โดยอ้างว่าสิ่งนี้ไม่เหมาะกับงานที่ผูกกับการคำนวณและไม่เข้ากันกับเธรดที่รันด้วยหลายระดับความสำคัญ
  • ผู้เขียนเสนอว่ารูปแบบ single ownership ของ Rust แม้จะเป็นความต้องการที่พบได้ทั่วไปเมื่อมี back reference แต่กลับยากเกินไปที่จะนำไปใช้งาน
  • ผู้เขียนเชื่อว่า ecosystem ด้านเกมของ Rust ยังไม่พร้อมสำหรับการพัฒนาเกมอย่างจริงจัง โดยยกเรื่องการขาดแคลนกราฟิกที่ไม่ใช่ระดับของเล่นใน Rust ขึ้นมาเป็นตัวอย่าง
  • ความเห็นอื่น ๆ เห็นด้วยว่า async Rust นั้นท้าทายและมักไม่จำเป็น พร้อมเสนอว่าแนวทางของ Go ที่ทำทุกอย่างให้เป็น sync แล้วมี async channel เพียงช่องเดียวอาจดีกว่า
  • ผู้แสดงความคิดเห็นบางส่วนวิจารณ์การใช้ async อย่างแพร่หลายใน ecosystem ของ Rust โดยอ้างว่ามันบีบให้โปรแกรมต้องเป็น async ไปทั้งระบบ หรือไม่ก็ต้องพึ่งพา crate อย่าง tokio สำหรับหลายอย่าง
  • ผู้แสดงความคิดเห็นบางส่วนเสนอว่าความสามารถด้าน async ของ Rust ยังอยู่ระหว่างการพัฒนา และการวิจารณ์สถานะปัจจุบันอาจยังเร็วเกินไป
  • ผู้แสดงความคิดเห็นรายหนึ่งโต้แย้งว่า Arc ของ Rust ไม่ได้เป็นสิ่งที่คาดเดาไม่ได้ แต่ขึ้นอยู่กับว่าถูกถือครองไว้ที่ไหนและอย่างไร และเสนอว่าผู้เขียนกำลังพยายามยัดกรอบความคิดเดิมของตนใส่ Rust
  • ผู้แสดงความคิดเห็นบางส่วนคัดค้านการใช้ async/await โดยทั่วไป โดยอ้างว่าสิ่งนี้ทำให้ภาษาและ ecosystem ถูกแบ่งออกเป็นสองฝั่งและจะก่อปัญหาในระยะยาว
  • ผู้แสดงความคิดเห็นรายหนึ่งเสนอว่า primitive ที่ถูกต้องสำหรับ concurrency คือ Hoare's Communicating Sequential Processes ซึ่งแมปกับ green threads ได้ เหมือนที่มีการนำไปใช้ใน Java (ตั้งแต่ JDK17 - Java Virtual Threads), Go และ Kotlin
  • ผู้แสดงความคิดเห็นรายหนึ่งเสนอว่าการใช้ crate ที่ไม่ปลอดภัยอย่าง async-scoped เพื่อจับบั๊กส่วนใหญ่ที่ถ้าเป็น C++ ก็น่าจะเขียนขึ้นมา เป็นการประนีประนอมที่สมเหตุสมผล