0Pricing
Learn Rust Coding · บทเรียน

แชนเนล Crossbeam

แชนเนลขั้นสูง

แชนเนล Crossbeam เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Learn Rust Coding และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

นอกเหนือจาก std mpsc

แชนเนล mpsc ของไลบรารีมาตรฐานเป็นแบบผู้บริโภคเดี่ยว: มีตัวรับเพียงหนึ่งตัว crate crossbeam-channel มีแชนเนลแบบผู้ผลิตหลายราย ผู้บริโภคหลายราย (mpmc) พร้อมความสามารถที่มากกว่าและมักมีประสิทธิภาพดีกว่า

จุดเด่น:

  • โคลน Receiver ได้ ไม่ใช่แค่ผู้ส่ง
  • แมโคร select! ที่ทรงพลังสำหรับรอหลายแชนเนล
  • แชนเนลแบบมีขอบเขต ไม่จำกัดขอบเขต และแชนเนลพิเศษอย่างแชนเนลส่งสัญญาณเป็นช่วง

การเพิ่มสิ่งที่ต้องพึ่งพา

Crossbeam เป็น crate ภายนอก ดังนั้นให้เพิ่มลงใน Cargo.toml:

[dependencies]
crossbeam-channel = "0.5"

จากนั้นนำเข้าฟังก์ชันของมัน เนื่องจากตัวอย่างนี้ต้องใช้ Cargo และ crate ภายนอก โค้ดตัวอย่างจึงแสดงการใช้งานส่วนติดต่อโปรแกรมแทนที่จะทำงานได้โดยลำพัง

// Cargo.toml
// [dependencies]
// crossbeam-channel = "0.5"

use crossbeam_channel::unbounded;

fn main() {
    let (s, r) = unbounded();
    s.send("hello").unwrap();
    println!("{}", r.recv().unwrap());
}

แบบไม่จำกัดและแบบมีขอบเขต

Crossbeam มีตัวสร้างหลักสองแบบ:

  • unbounded() จะขยายตามความจำเป็น และ send จะไม่บล็อก
  • bounded(cap) มีบัฟเฟอร์ขนาดคงที่ โดย send จะบล็อกเมื่อบัฟเฟอร์เต็ม ทำให้เกิดแรงดันย้อนกลับ

แชนเนล bounded(0) เป็นแชนเนลแบบพบกัน ซึ่งการส่งและการรับจะส่งต่อข้อมูลถึงกันโดยตรง

use crossbeam_channel::bounded;
use std::thread;

fn main() {
    let (s, r) = bounded(2);
    thread::spawn(move || {
        for i in 1..=3 {
            s.send(i).unwrap();
        }
    });
    while let Ok(v) = r.recv() {
        println!("got {}", v);
    }
}

ผู้บริโภคหลายราย

ข้อได้เปรียบสำคัญคือ คุณสามารถโคลน Receiver ได้ เธรดผู้ปฏิบัติงานหลายเธรดสามารถดึงข้อมูลจากแชนเนลเดียวกัน และแต่ละข้อความจะถูกส่งให้เธรดใดเธรดหนึ่งเพียงเธรดเดียว นี่คือรากฐานของกลุ่มเธรดที่แย่งงานกันทำ

use crossbeam_channel::unbounded;
use std::thread;

fn main() {
    let (s, r) = unbounded();
    let mut workers = vec![];
    for id in 0..3 {
        let rx = r.clone();
        workers.push(thread::spawn(move || {
            while let Ok(job) = rx.recv() {
                println!("worker {} got job {}", id, job);
            }
        }));
    }
    for job in 0..6 { s.send(job).unwrap(); }
    drop(s);
    for w in workers { w.join().unwrap(); }
}

แมโคร select!

select! ช่วยให้เธรดหนึ่งรอการดำเนินการจากหลายแชนเนล และดำเนินการกับรายการที่พร้อมก่อน มันคล้ายกับ match ที่ทำงานกับเหตุการณ์ของแชนเนล จึงเหมาะสำหรับรวมข้อมูลนำเข้าจากหลายแหล่ง

use crossbeam_channel::{unbounded, select};
use std::thread;

fn main() {
    let (s1, r1) = unbounded();
    let (s2, r2) = unbounded();
    thread::spawn(move || { s1.send("from one").unwrap(); });
    thread::spawn(move || { s2.send("from two").unwrap(); });
    for _ in 0..2 {
        select! {
            recv(r1) -> msg => println!("r1: {}", msg.unwrap()),
            recv(r2) -> msg => println!("r2: {}", msg.unwrap()),
        }
    }
}

การหมดเวลารอด้วย select!

select! รองรับแขนง default และแขนงตัวจับเวลา recv(after(duration)) คุณจึงยกเลิกการรอได้เมื่อถึงเวลาหมด แทนที่จะบล็อกตลอดไป สิ่งนี้จำเป็นอย่างยิ่งสำหรับระบบที่ตอบสนองได้ดี

use crossbeam_channel::{unbounded, select, after};
use std::time::Duration;

fn main() {
    let (_s, r) = unbounded::<i32>();
    select! {
        recv(r) -> msg => println!("received {:?}", msg),
        recv(after(Duration::from_millis(100))) -> _ => {
            println!("timed out waiting for a message");
        }
    }
}

try_send และ try_recv

เช่นเดียวกับไลบรารีมาตรฐาน crossbeam มีรูปแบบที่ไม่บล็อกด้วย try_send จะล้มเหลวทันทีหากแชนเนลแบบมีขอบเขตเต็ม ส่วน try_recv จะล้มเหลวทันทีหากยังไม่มีข้อความพร้อมใช้งาน ทั้งสองอย่างจะคืนค่าข้อผิดพลาดที่อธิบายสาเหตุได้ ซึ่งคุณสามารถใช้ match ตรวจสอบได้

use crossbeam_channel::{bounded, TrySendError};

fn main() {
    let (s, _r) = bounded(1);
    s.send(1).unwrap();
    match s.try_send(2) {
        Ok(()) => println!("sent"),
        Err(TrySendError::Full(v)) => println!("full, kept {}", v),
        Err(TrySendError::Disconnected(v)) => println!("closed, kept {}", v),
    }
}

tick และงานตามช่วงเวลา

ฟังก์ชัน tick(duration) จะคืนค่าตัวรับที่ส่งข้อความตามช่วงเวลาคงที่ คุณสามารถใช้ร่วมกับ select! เพื่อเรียกใช้งานเป็นระยะควบคู่ไปกับแชนเนลอื่น เช่น สัญญาณชีพหรือวงรอบตรวจสอบ

use crossbeam_channel::{tick, select};
use std::time::Duration;

fn main() {
    let ticker = tick(Duration::from_millis(50));
    let mut count = 0;
    while count < 3 {
        select! {
            recv(ticker) -> _ => {
                count += 1;
                println!("tick {}", count);
            }
        }
    }
}

ไปป์ไลน์ของขั้นตอนต่าง ๆ

Crossbeamโดดเด่นในการสร้างไปป์ไลน์: ขั้นที่หนึ่งสร้างข้อมูล ขั้นที่สองแปลงข้อมูล และขั้นที่สามนำข้อมูลไปใช้ แต่ละขั้นทำงานบนเธรดของตนเองที่เชื่อมต่อกันด้วยแชนเนล และตัวรับที่โคลนแล้วช่วยให้คุณขยายขั้นใดก็ได้ไปทำงานกับผู้ปฏิบัติงานหลายตัว

use crossbeam_channel::unbounded;
use std::thread;

fn main() {
    let (in_s, in_r) = unbounded();
    let (out_s, out_r) = unbounded();
    thread::spawn(move || {
        for n in in_r { out_s.send(n * n).unwrap(); }
    });
    for n in 1..=4 { in_s.send(n).unwrap(); }
    drop(in_s);
    for sq in out_r { println!("square: {}", sq); }
}

เมื่อ Crossbeam เหนือกว่า std

เลือกใช้ crossbeam-channel เมื่อคุณต้องการ:

  • ผู้รับหลายตัวใช้คิวเดียวร่วมกัน (กลุ่มผู้ปฏิบัติงาน)
  • select! เพื่อรอจากหลายแชนเนลพร้อมกำหนดเวลาหมดเวลา
  • ตัวจับเวลาแบบเป็นช่วงผ่าน tick ซึ่งผสานเข้ากับการเลือก

สำหรับท่อแบบผู้ผลิตหนึ่งตัวและผู้บริโภคหนึ่งตัวอย่างง่าย mpsc มาตรฐานก็เพียงพอและไม่ต้องเพิ่มส่วนพึ่งพา

แชนเนลจะปิดเมื่อมีการทิ้ง

เช่นเดียวกับ std แชนเนลของ crossbeam จะปิดเมื่อผู้ส่งทั้งหมด (สำหรับฝั่งผู้รับ) หรือผู้รับทั้งหมด (สำหรับฝั่งผู้ส่ง) ถูกทิ้ง การวนซ้ำผ่านตัวรับจะสิ้นสุดลงหลังจากผู้ส่งตัวสุดท้ายถูกทิ้ง ควรใช้ drop หรือจำกัดขอบเขตของผู้ส่งเสมอ เพื่อให้ลูปของผู้ปฏิบัติงานออกได้อย่างเรียบร้อย

use crossbeam_channel::unbounded;
use std::thread;

fn main() {
    let (s, r) = unbounded();
    let h = thread::spawn(move || {
        let total: i32 = r.iter().sum();
        println!("total: {}", total);
    });
    for i in 1..=5 { s.send(i).unwrap(); }
    drop(s); // closes channel so the loop ends
    h.join().unwrap();
}

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจเกี่ยวกับแชนเนลของ crossbeam

สรุปทบทวน

คุณได้สำรวจแชนเนลของ crossbeam:

  • แชนเนลเหล่านี้เป็นแบบ mpmc กล่าวคือสามารถโคลนทั้งผู้ส่งและผู้รับได้
  • unbounded() และ bounded(n) ควบคุมการบัฟเฟอร์และแรงดันย้อนกลับ
  • select! รอจากหลายแชนเนล โดยกำหนดเวลาหมดเวลาด้วย after และใช้ tick สำหรับช่วงเวลาซ้ำ
  • try_send/try_recv ทำงานโดยไม่บล็อก
  • ใช้ crossbeam สำหรับกลุ่มผู้ปฏิบัติงานและไปป์ไลน์ที่ซับซ้อน ส่วน std mpsc เหมาะกับท่อแบบง่าย

คำถามที่พบบ่อย

บทเรียน “แชนเนล Crossbeam” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “แชนเนล Crossbeam” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Learn Rust Coding ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “แชนเนล Crossbeam”

แชนเนลขั้นสูง คุณปฏิบัติ Learn Rust Coding ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Learn Rust Coding หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Learn Rust Coding บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “แชนเนล Crossbeam” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Learn Rust Coding นี้ได้ไหม

ได้ บทเรียน Learn Rust Coding ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. แชนเนล mpsc
  2. การแบ่งปันสถานะด้วย Arc/Mutex
  3. เธรดตามขอบเขต
  4. แชนเนล Crossbeam
← กลับไปที่ Learn Rust Coding