Concurrency ที่ขยายได้ด้วย Send และ Sync
น่าสนใจ ฟีเจอร์ concurrency เกือบทุกอย่างที่เราพูดถึงในบทนี้เป็นส่วน ของ standard library ไม่ใช่ภาษา ตัวเลือกของคุณสำหรับการจัดการ concurrency ไม่จำกัดอยู่ที่ภาษาหรือ standard library — คุณเขียน ฟีเจอร์ concurrency ของคุณเองหรือใช้ที่เขียนโดยคนอื่นได้
อย่างไรก็ตาม ในหมู่แนวคิด concurrency หลักที่ฝังในภาษาไม่ใช่ standard
library คือ trait std::marker Send และ Sync
โอน Ownership ระหว่าง Thread
trait marker Send ระบุว่า ownership ของค่าของ type ที่ implement
Send โอนได้ระหว่างเธรด เกือบทุก type Rust implement Send แต่
มีข้อยกเว้นบางอย่าง รวม Rc<T> — นี่ implement Send ไม่ได้
เพราะถ้าคุณ clone ค่า Rc<T> และพยายามโอน ownership ของ clone ไปยัง
อีกเธรด ทั้งสองเธรดอาจอัพเดท reference count พร้อมกัน ด้วยเหตุผลนี้
Rc<T> ถูก implement สำหรับใช้ในสถานการณ์เธรดเดียวที่คุณไม่ต้องการ
จ่ายบทลงโทษ performance ที่ thread-safe
ดังนั้น ระบบ type และ trait bound ของ Rust รับประกันว่าคุณส่งค่า
Rc<T> ข้ามเธรดอย่างไม่ปลอดภัยโดยบังเอิญไม่ได้ เมื่อเราพยายามทำสิ่ง
นี้ใน Listing 16-14 เราได้ error
the trait `Send` is not implemented for `Rc<Mutex<i32>>` เมื่อ
เราเปลี่ยนเป็น Arc<T> ซึ่ง implement Send โค้ดคอมไพล์
type ใดที่ประกอบด้วย type Send ทั้งหมดถูกทำเครื่องหมายเป็น Send
อัตโนมัติด้วย เกือบทั้งหมดของ primitive type เป็น Send ยกเว้น
raw pointer ที่เราจะพูดถึงในบทที่ 20
เข้าถึงจากหลาย Thread
trait marker Sync ระบุว่ามันปลอดภัยสำหรับ type ที่ implement
Sync ที่จะถูกอ้างถึงจากหลายเธรด อีกนัยหนึ่ง type T ใด implement
Sync ถ้า &T (immutable reference ของ T) implement Send
หมายความว่า reference ส่งได้ปลอดภัยไปยังอีกเธรด คล้ายกับ Send
primitive type ทั้งหมด implement Sync และ type ที่ประกอบด้วย type
ที่ implement Sync ทั้งหมดก็ implement Sync ด้วย
smart pointer Rc<T> ก็ไม่ implement Sync ด้วยเหตุผลเดียวกับที่
มันไม่ implement Send type RefCell<T> (ที่เราพูดถึงในบทที่ 15)
และตระกูลของ type Cell<T> ที่เกี่ยวข้องไม่ implement Sync
implementation ของ borrow checking ที่ RefCell<T> ทำที่ runtime
ไม่ thread-safe smart pointer Mutex<T> implement Sync และใช้
แชร์การเข้าถึงกับหลายเธรดได้ ดังที่คุณเห็นใน
“การเข้าถึง Mutex<T> แบบแชร์”
Implement Send และ Sync ด้วยมือเป็น Unsafe
เพราะ type ที่ประกอบด้วย type อื่นที่ implement trait Send และ
Sync ก็ implement Send และ Sync อัตโนมัติ เราไม่ต้อง implement
trait เหล่านั้นด้วยมือ ในฐานะ marker trait พวกมันไม่มีเมธอดให้
implement ด้วย พวกมันเพียงมีประโยชน์ในการบังคับใช้ invariant ที่
เกี่ยวกับ concurrency
การ implement trait เหล่านี้ด้วยมือเกี่ยวข้องกับการ implement โค้ด
unsafe Rust เราจะพูดถึงการใช้โค้ด unsafe Rust ในบทที่ 20 — ตอนนี้
ข้อมูลที่สำคัญคือการ build type concurrent ใหม่ที่ไม่ประกอบด้วย
ส่วน Send และ Sync ต้องการความคิดอย่างระวังเพื่อรักษาการรับ
ประกันความปลอดภัย “The Rustonomicon” มีข้อมูลเพิ่มเกี่ยว
กับการรับประกันเหล่านี้และวิธีรักษาพวกมัน
สรุป
นี่ไม่ใช่ครั้งสุดท้ายที่คุณจะเห็น concurrency ในหนังสือเล่มนี้ — บท ถัดไปโฟกัสที่ async programming และโปรเจกต์ในบทที่ 21 จะใช้แนวคิด ในบทนี้ในสถานการณ์ที่ realistic มากกว่าตัวอย่างเล็กกว่าที่พูดถึง ที่นี่
ดังที่กล่าวก่อนหน้า เพราะน้อยมากของวิธีที่ Rust จัดการ concurrency เป็นส่วนของภาษา วิธีแก้ concurrency หลายอย่างถูก implement เป็น crate เหล่านี้พัฒนาเร็วกว่า standard library ดังนั้นอย่าลืมค้นหา online สำหรับ crate ปัจจุบันและ state-of-the-art ที่จะใช้ใน สถานการณ์ multithreaded
standard library ของ Rust ให้ channel สำหรับ message passing และ
type smart pointer เช่น Mutex<T> และ Arc<T> ที่ปลอดภัยที่จะใช้
ใน context concurrent ระบบ type และ borrow checker รับประกันว่า
โค้ดที่ใช้วิธีแก้เหล่านี้จะไม่ลงเอยด้วย data race หรือ reference
ที่ไม่ valid เมื่อคุณทำให้โค้ดของคุณคอมไพล์ คุณวางใจได้ว่ามันจะ
รันอย่างมีความสุขบนหลายเธรดโดยไม่มี bug ที่ track ลงยากที่ทั่วไป
ในภาษาอื่น Concurrent programming ไม่ใช่แนวคิดที่จะกลัวอีก — ไปข้าง
หน้าและทำให้โปรแกรมของคุณ concurrent อย่างไม่กลัว!