รอเธรดและรวบรวมผลลัพธ์
รอเธรดและรวบรวมผลลัพธ์
รอเธรดและรวบรวมผลลัพธ์ เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Learn Rust Coding และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน
ทำไมต้อง join เธรด
การสร้างเธรดจะเริ่มงาน แต่โดยทั่วไปคุณมักต้องการผลลัพธ์ของงาน หรืออย่างน้อยต้องการยืนยันว่างานเสร็จแล้ว การ join คือวิธีรอให้เธรดทำงานเสร็จ
ในบทเรียนนี้คุณจะรวบรวมตัวจัดการ join ตัวจัดการเหล่านั้น และรวบรวมค่าที่เธรดสร้างขึ้นเป็นคำตอบสุดท้าย
join คืนค่าเป็น Result
join คืนค่าเป็น Result เมื่อสำเร็จ ค่านี้จะเก็บค่าที่โคลเชอร์คืนมา แต่หากเธรดเกิดพานิก ค่านี้จะเก็บ Err
การเรียก unwrap จะให้ค่าโดยตรง แต่จะส่งต่อพานิกหากเธรดทำงานล้มเหลว
use std::thread;
fn main() {
let h = thread::spawn(|| 7 * 6);
let value: i32 = h.join().unwrap();
println!("answer = {}", value);
}รวบรวมตัวจัดการก่อน
หากต้องการให้เธรดทำงานแบบขนาน ให้สร้างเธรดทั้งหมดก่อน แล้วค่อย join เธรดใด ๆ ให้เพิ่มตัวจัดการแต่ละตัวลงในเวกเตอร์ไปเรื่อย ๆ
หาก join ภายในลูปที่สร้างเธรด แต่ละเธรดจะต้องทำงานเสร็จก่อนที่เธรดถัดไปจะเริ่ม และคุณจะสูญเสียการทำงานพร้อมกัน
use std::thread;
fn main() {
let handles: Vec<_> = (0..4)
.map(|i| thread::spawn(move || i * i))
.collect();
for h in handles {
println!("{}", h.join().unwrap());
}
}รวบรวมผลลัพธ์ลงใน Vec
คุณสามารถ join ตัวจัดการทุกตัว แล้วเพิ่มค่าที่คืนลงในเวกเตอร์ผลลัพธ์
ลำดับการสร้างและลำดับการ join ในที่นี้ทำงานตั้งแต่ศูนย์ถึงสามเหมือนกัน ดังนั้นเวกเตอร์ผลลัพธ์จึงมีลำดับที่คาดเดาได้
use std::thread;
fn main() {
let handles: Vec<_> = (1..=4)
.map(|n| thread::spawn(move || n * 10))
.collect();
let results: Vec<i32> = handles
.into_iter()
.map(|h| h.join().unwrap())
.collect();
println!("{:?}", results);
}รวมผลลัพธ์แบบขนาน
เมื่อรวบรวมผลลัพธ์แล้ว คุณสามารถลดผลลัพธ์เหล่านั้นได้ ในที่นี้แต่ละเธรดคำนวณค่าบางส่วน แล้ว main รวมค่าทั้งหมด
รูปแบบ map แล้ว reduce นี้เป็นรูปแบบการทำงานแบบขนานที่ใช้กันทั่วไป
use std::thread;
fn main() {
let handles: Vec<_> = (1..=5)
.map(|n| thread::spawn(move || n * n))
.collect();
let total: i32 = handles
.into_iter()
.map(|h| h.join().unwrap())
.sum();
println!("total = {}", total);
}แบ่งงานเป็นส่วนย่อย
สำหรับข้อมูลขนาดใหญ่ ให้แบ่งข้อมูลเป็นส่วนย่อยและมอบแต่ละส่วนให้เธรดของตนเอง แต่ละเธรดจะคืนผลรวมบางส่วน
การโคลนแต่ละส่วนลงใน Vec ที่เป็นเจ้าของข้อมูล ทำให้เธรดเป็นเจ้าของสไลซ์ของตนเองได้อย่างปลอดภัย
use std::thread;
fn main() {
let data: Vec<i32> = (1..=10).collect();
let handles: Vec<_> = data
.chunks(5)
.map(|c| { let c = c.to_vec(); thread::spawn(move || c.iter().sum::<i32>()) })
.collect();
let total: i32 = handles.into_iter().map(|h| h.join().unwrap()).sum();
println!("{}", total);
}จัดการพานิกของเธรด
หากมีโอกาสที่เธรดผู้ทำงานจะเกิดพานิก อย่าใช้ unwrap โดยไม่ตรวจสอบ ให้จับคู่กับ Result จาก join เพื่อจัดการเส้นทางข้อผิดพลาด
วิธีนี้ช่วยให้เธรดหลักยังทำงานต่อได้ แม้ผู้ทำงานรายหนึ่งจะล้มเหลว
use std::thread;
fn main() {
let h = thread::spawn(|| {
if true { panic!("failed"); }
1
});
match h.join() {
Ok(v) => println!("got {}", v),
Err(_) => println!("thread panicked"),
}
}รวบรวมลงใน Vec ที่ใช้ร่วมกัน
แทนที่จะคืนค่า เธรดสามารถเพิ่มค่าลงใน Arc<Mutex<Vec>> ที่ใช้ร่วมกันได้ ลำดับของค่าจึงไม่แน่นอน
หลังจาก join เธรดทั้งหมดแล้ว ให้ล็อกเวกเตอร์หนึ่งครั้งเพื่ออ่านผลลัพธ์ที่รวบรวมไว้ทั้งหมด
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let out = Arc::new(Mutex::new(vec![]));
let mut handles = vec![];
for i in 0..3 {
let o = Arc::clone(&out);
handles.push(thread::spawn(move || o.lock().unwrap().push(i)));
}
for h in handles { h.join().unwrap(); }
println!("{:?}", out.lock().unwrap());
}เธรดแบบกำหนดขอบเขต
thread::scope ช่วยให้เธรดยืมข้อมูลท้องถิ่นได้โดยไม่ต้องใช้ move หรือ Arc ขอบเขตจะรับประกันว่าเธรดทั้งหมดทำงานเสร็จก่อนที่ขอบเขตจะคืนค่า
วิธีนี้ทำให้การอ่านข้อมูลบนสแตกแบบขนานทำได้สะดวกและปลอดภัย
use std::thread;
fn main() {
let data = vec![1, 2, 3];
thread::scope(|s| {
s.spawn(|| println!("sum {}", data.iter().sum::<i32>()));
s.spawn(|| println!("len {}", data.len()));
});
}คืนผลลัพธ์จากขอบเขต
เธรดแบบกำหนดขอบเขตสามารถคืนค่าผ่านตัวจัดการของตนได้เช่นกัน คุณ join เธรดเหล่านั้นภายในขอบเขตเพื่อรวบรวมผลลัพธ์
เนื่องจากขอบเขตจะบล็อกจนกว่างานจะเสร็จ ข้อมูลที่ยืมมาจึงยังใช้งานได้ตลอดเวลา
use std::thread;
fn main() {
let nums = vec![4, 5, 6];
let total = thread::scope(|s| {
let h = s.spawn(|| nums.iter().sum::<i32>());
h.join().unwrap()
});
println!("total = {}", total);
}อย่าลืม join
หากคุณทิ้ง JoinHandle โดยไม่ join เธรดจะถูกแยกออกจากเจ้าของ เธรดยังคงทำงานต่อ แต่คุณจะสูญเสียทั้งผลลัพธ์และวิธีรอเธรดนั้น
กระบวนการอาจจบลงก่อนที่เธรดที่ถูกแยกจะทำงานเสร็จด้วย ดังนั้นควร join เมื่อคุณต้องการผลลัพธ์หรือการยืนยันว่าเสร็จแล้ว
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจของคุณเกี่ยวกับการ join และการรวบรวมผลลัพธ์
สรุป
คุณได้เรียนรู้ว่า join คืนค่าเป็น Result ซึ่งเก็บค่าหรือพานิกของเธรดไว้ ให้สร้างเธรดทั้งหมดก่อน แล้วจึง join เพื่อรักษาการทำงานแบบขนาน
คุณสามารถรวบรวมผลลัพธ์ลงใน Vec ลดผลลัพธ์เหล่านั้น หรือเพิ่มค่าลงใน Arc<Mutex<Vec>> ที่ใช้ร่วมกันได้ เธรดแบบกำหนดขอบเขตสามารถยืมข้อมูลท้องถิ่นได้อย่างปลอดภัย และการทิ้งตัวจัดการจะทำให้เธรดถูกแยกออก
ตอนนี้คุณมีเครื่องมือพื้นฐานสำหรับเธรดและสถานะที่ใช้ร่วมกันใน Rust แล้ว
เรียนรู้ Rust ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 39
- บทเรียน
- 144
คำถามที่พบบ่อย
บทเรียน “รอเธรดและรวบรวมผลลัพธ์” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “รอเธรดและรวบรวมผลลัพธ์” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Learn Rust Coding ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “รอเธรดและรวบรวมผลลัพธ์”
รอเธรดและรวบรวมผลลัพธ์ คุณปฏิบัติ Learn Rust Coding ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Learn Rust Coding หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Learn Rust Coding บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “รอเธรดและรวบรวมผลลัพธ์” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Learn Rust Coding นี้ได้ไหม
ได้ บทเรียน Learn Rust Coding ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- สร้างเธรด
- ย้ายข้อมูลเข้าเธรด
- ใช้ข้อมูลร่วมกับ Arc และ Mutex
- รอเธรดและรวบรวมผลลัพธ์