แชนเนล 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- แชนเนล mpsc
- การแบ่งปันสถานะด้วย Arc/Mutex
- เธรดตามขอบเขต
- แชนเนล Crossbeam