Concurrency, Testing & Cargo
Fearless Concurrency — สิ่งที่จะได้เรียนในโมดูลนี้
หัวข้อที่มีชื่อว่า “Fearless Concurrency — สิ่งที่จะได้เรียนในโมดูลนี้”หนึ่งในข้อเรียกร้องที่กล้าหาญที่สุดของ Rust คือ fearless concurrency (การทำงานพร้อมกันอย่างไม่หวั่นเกรง): การเขียนโปรแกรมแบบหลาย-thread โดยไม่มี data race ที่รบกวน C, C++ หรือแม้แต่ Java คอมไพเลอร์บังคับใช้กฎ ownership เดิมที่ขอบเขตของ thread เปลี่ยนบั๊กทั้งคลาสให้เป็น compile-time error แทนที่จะเป็น runtime failure ที่หาได้ยาก
โมดูลนี้สำรวจสี่เสาหลักของ Rust ในการใช้งานจริง:
| บทเรียน | หัวข้อ | รันได้ |
|---|---|---|
| Threads | std::thread, Arc<Mutex<T>>, การ join handle | ได้ — Playground ใน browser |
| Channels | std::sync::mpsc, send/receive, การส่งต่อ ownership | ได้ — Playground ใน browser |
| Async Intro | async/.await, futures, tokio runtime | เฉพาะ Cargo project เท่านั้น |
| Cargo & Tests | cargo new, #[test], cargo test | เฉพาะ Cargo project เท่านั้น |
สองโมเดลของ Concurrency
หัวข้อที่มีชื่อว่า “สองโมเดลของ Concurrency”standard library ของ Rust มี OS threads ผ่าน std::thread แต่ละ thread คือ thread ระดับ OS จริง ๆ ที่มี stack ของตัวเอง สถานะที่แชร์กันระหว่าง thread ถูกป้องกันด้วย Arc<Mutex<T>> — คอมไพเลอร์จะไม่ยอมให้คุณส่งประเภทที่ไม่ใช่ Send ข้ามขอบเขต thread
สำหรับ workload ที่ผูกติดกับ I/O — network server, การดำเนินการกับไฟล์, งานที่เกิดขึ้นพร้อมกันจำนวนมาก — โมเดล async/.await มีประสิทธิภาพมากกว่า โดยใช้ event loop แบบ single-threaded หรือ multi-threaded (โดยทั่วไปคือ tokio) เพื่อกำหนดเวลาของงานนับพัน ๆ งานโดยไม่มีค่าใช้จ่ายของ OS thread ต่องาน
ทำไม Concurrency ใน Rust จึงแตกต่าง
หัวข้อที่มีชื่อว่า “ทำไม Concurrency ใน Rust จึงแตกต่าง”ในภาษาส่วนใหญ่ data race คือปัญหา runtime คุณเขียนโค้ด รันขึ้นมา และบางครั้งโปรแกรมก็ crash หรือส่งคืนผลลัพธ์ที่ผิดเมื่อมีการโหลดสูง ใน Rust:
- ประเภทที่เป็น
Sendหมายความว่าปลอดภัยที่จะย้ายไปยัง thread อื่น - ประเภทที่เป็น
Syncหมายความว่าปลอดภัยที่จะแชร์ reference ข้าม thread - คอมไพเลอร์ปฏิเสธโค้ดที่ละเมิดสัญญาเหล่านี้ — ไม่ต้องการ sanitizer หรือ runtime check
ตัวอย่างสั้น ๆ
หัวข้อที่มีชื่อว่า “ตัวอย่างสั้น ๆ”นี่คือโปรแกรม Rust แบบ concurrent ที่เล็กที่สุดที่มีความหมาย — spawn thread รอ แล้วทำงานต่อใน main
use std::thread;
fn main() { let handle = thread::spawn(|| { println!("Hello from a spawned thread!"); }); handle.join().unwrap(); println!("Main thread done.");}Compiling…