Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 อย่างไม่กลัว!