Send และ Sync
ปัญหา: การแชร์ข้อมูลข้าม threads
หัวข้อที่มีชื่อว่า “ปัญหา: การแชร์ข้อมูลข้าม threads”JavaScript หลีกเลี่ยงปัญหา thread-safety โดยสิ้นเชิง — มีแค่ thread เดียว (ต่อ Worker) ดังนั้นคำถามที่ว่า “สอง thread สามารถเข้าถึงค่านี้พร้อมกันได้ไหม?” จึงไม่เกิดขึ้นเลย ไม่มีแนวคิด thread safety ระดับ type ใน TypeScript
Rust รองรับ parallelism จริง แปลว่าสอง thread เข้าถึง memory ก้อนเดียวกันพร้อมกันได้จริง ๆ เพื่อให้ปลอดภัยโดยไม่ต้องพึ่ง garbage collector หรือ lock ตอน runtime ทาง Rust เลยใช้ marker trait สองตัว: Send และ Sync
นิยามของ Send และ Sync
หัวข้อที่มีชื่อว่า “นิยามของ Send และ Sync”| Trait | ความหมาย | ตัวอย่าง type |
|---|---|---|
Send | ค่าของ type T สามารถ ย้าย ไปยัง thread อื่นได้ | i32, String, Vec<T>, Arc<T> |
Sync | shared reference &T สามารถส่งไปยัง thread อื่นได้ | i32, Arc<T>, Mutex<T> |
ไม่ใช่ Send | ไม่สามารถย้ายไปยัง thread อื่นได้ | Rc<T> (non-atomic reference count) |
ไม่ใช่ Sync | ไม่สามารถแชร์ reference ข้าม threads ได้ | Cell<T>, RefCell<T> |
trait สองตัวนี้ compiler implement ให้อัตโนมัติ โดยดูจาก type ที่อยู่ภายใน struct ของคุณ แทบไม่มีเคสที่ต้อง implement เอง และกฎจะ propagate ต่อ: ถ้า struct มี field ตัวใดไม่ใช่ Send ตัว struct เองก็ไม่ใช่ Send ด้วย
// TypeScript ไม่มี type สำหรับ thread-safety// ภาษารับประกันความปลอดภัยโดยมีแค่ thread เดียวต่อ Worker// ไม่มีแนวคิด Send หรือ Sync ระดับ type
// ใน Worker คุณสื่อสารได้เฉพาะผ่าน structured-clone (postMessage):// plain objects, arrays, ArrayBuffer ฯลฯ// ไม่สามารถส่ง class instance ที่มี methods, closure, หรือ WeakRef ได้
const worker = new Worker('./worker.js');// นี่ ทำงานได้: number เป็น structured-cloneableworker.postMessage(42);// นี่จะ FAIL ณ runtime: functions ไม่สามารถ clone ได้// worker.postMessage(() => 42); // DataCloneError// Rust: Send/Sync เป็นการรับประกัน ณ compile time ไม่ใช่ runtime checks
use std::sync::{Arc, Mutex};use std::thread;
fn main() { // Arc<Mutex<T>> ทั้ง Send และ Sync: // - Arc: thread-safe reference counting (vs Rc ที่ไม่ใช่ Send) // - Mutex: ให้ interior mutability พร้อม lock let shared: Arc<Mutex<Vec<u32>>> = Arc::new(Mutex::new(vec![])); let mut handles = vec![];
for i in 0..4 { let data = Arc::clone(&shared); // clone ราคาถูก — แค่ increment pointer let h = thread::spawn(move || { data.lock().unwrap().push(i); // lock, push, auto-unlock }); handles.push(h); }
for h in handles { h.join().unwrap(); }
let mut result = shared.lock().unwrap().clone(); result.sort(); println!("collected: {:?}", result); // collected: [0, 1, 2, 3]}ลองรันเลย — เวอร์ชันที่ทำงานได้กับ Arc
หัวข้อที่มีชื่อว่า “ลองรันเลย — เวอร์ชันที่ทำงานได้กับ Arc”use std::sync::{Arc, Mutex};use std::thread;
fn main() { let data: Arc<Mutex<Vec<u32>>> = Arc::new(Mutex::new(vec![])); let mut handles = vec![];
for i in 0..4 { let d = Arc::clone(&data); let h = thread::spawn(move || { d.lock().unwrap().push(i); }); handles.push(h); }
for h in handles { h.join().unwrap(); }
let mut result = data.lock().unwrap().clone(); result.sort(); println!("collected: {:?}", result);}Compiling…