สร้างเธรด
เรียกใช้โค้ดพร้อมกัน
สร้างเธรด เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Learn Rust Coding และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน
เธรดคืออะไร
เธรดช่วยให้โปรแกรมเรียกใช้โค้ดพร้อมกันได้ ระบบปฏิบัติการสามารถจัดตารางเวลาให้หลายเธรดทำงานได้ จึงทำให้งานต่าง ๆ ทำงานทับซ้อนกันได้
ไลบรารีมาตรฐานของ Rust เปิดให้ใช้งานเธรดผ่านโมดูล std::thread เธรดเหล่านี้เป็นเธรดระดับระบบปฏิบัติการ หรือบางครั้งเรียกว่าเธรดแบบ 1:1
ในบทเรียนนี้ คุณจะเรียนรู้การเริ่มเธรดใหม่และควบคุมการทำงานของเธรดเหล่านั้น
การสร้างเธรดด้วย thread::spawn
คุณสร้างเธรดใหม่ได้โดยเรียก thread::spawn และส่งคลอเชอร์ให้ คลอเชอร์จะบรรจุโค้ดที่เธรดใหม่ต้องทำงาน
การเรียกใช้จะคืนค่าทันทีเป็น JoinHandle ขณะที่เธรดที่สร้างขึ้นทำงานอยู่เบื้องหลัง
use std::thread;
fn main() {
thread::spawn(|| {
println!("hello from a thread");
});
println!("hello from main");
}main อาจทำงานเสร็จก่อน
เมื่อ main คืนค่า กระบวนการทั้งหมดจะสิ้นสุดลง แม้เธรดที่สร้างขึ้นจะยังทำงานอยู่ก็ตาม
ดังนั้นโปรแกรมด้านบนอาจพิมพ์ออกมาเพียงข้อความจาก main เธรดเบื้องหลังอาจไม่มีโอกาสทำงานก่อนกระบวนการจะสิ้นสุด
เราจึงต้องมีวิธีรอให้เธรดทำงานเสร็จ
การรอด้วย join
JoinHandle ที่ได้จาก spawn มีเมธอด join การเรียกใช้เมธอดนี้จะบล็อกเธรดปัจจุบันจนกว่าเธรดที่สร้างขึ้นจะทำงานเสร็จ
วิธีนี้รับรองว่าเธรดที่สร้างขึ้นจะทำงานจนเสร็จก่อนที่ main จะทำงานต่อ
use std::thread;
fn main() {
let handle = thread::spawn(|| {
println!("worker done");
});
handle.join().unwrap();
println!("main done");
}เอาต์พุตสลับแทรกกัน
เมื่อเธรดสองตัวทำงานพร้อมกัน เอาต์พุตของทั้งคู่อาจสลับแทรกกันในรูปแบบที่คาดเดาไม่ได้ ระบบปฏิบัติการเป็นผู้กำหนดตารางการทำงาน
การเรียกใช้โปรแกรมเดิมสองครั้งอาจให้ลำดับที่ต่างกัน อย่าพึ่งพาลำดับที่เฉพาะเจาะจงหากไม่มีการประสานงาน
use std::thread;
fn main() {
let handle = thread::spawn(|| {
for i in 1..4 {
println!("thread: {}", i);
}
});
for i in 1..4 {
println!("main: {}", i);
}
handle.join().unwrap();
}การหยุดชั่วคราวด้วย sleep
คุณหยุดเธรดชั่วคราวได้ด้วย thread::sleep ซึ่งรับค่า Duration การทำเช่นนี้จะคืนเวลาให้ CPU เพื่อให้เธรดอื่นทำงานต่อได้
การหยุดชั่วคราวมีประโยชน์ในตัวอย่างเพื่อให้เห็นการสลับแทรกได้ชัดเจนขึ้น แต่ไม่ควรใช้แทนการประสานงานจริง
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 1..4 {
println!("spawned: {}", i);
thread::sleep(Duration::from_millis(1));
}
});
thread::sleep(Duration::from_millis(10));
}การสร้างเธรดจำนวนมาก
คุณสามารถสร้างเธรดหลายตัวภายในลูป และรวบรวมตัวจัดการของเธรดเหล่านั้นไว้ในเวกเตอร์ได้
จากนั้นจึงวนซ้ำผ่านเวกเตอร์และเรียก join กับตัวจัดการแต่ละตัว เพื่อรับรองว่าเธรดทุกตัวทำงานเสร็จก่อนโปรแกรมจะจบ
use std::thread;
fn main() {
let mut handles = vec![];
for id in 0..3 {
let h = thread::spawn(move || {
println!("thread {}", id);
});
handles.push(h);
}
for h in handles {
h.join().unwrap();
}
}การตั้งชื่อเธรดด้วย Builder
ชนิด thread::Builder ช่วยให้คุณกำหนดค่าเธรดก่อนสร้างได้ คุณสามารถตั้งชื่อและขนาดสแตกได้
เธรดที่มีชื่อทำให้ข้อความแพนิกและการแก้ไขข้อผิดพลาดอ่านได้ง่ายขึ้น
use std::thread;
fn main() {
let h = thread::Builder::new()
.name("worker".into())
.spawn(|| {
println!("running in named thread");
})
.unwrap();
h.join().unwrap();
}แพนิกยังคงอยู่ภายในเธรด
หากเธรดที่สร้างขึ้นเกิดแพนิก โดยค่าเริ่มต้นจะไม่ทำให้โปรแกรมทั้งหมดหยุดทำงาน แพนิกจะถูกจำกัดอยู่ภายในเธรดนั้น
เมื่อคุณเรียก join กับเธรดที่เกิดแพนิก คุณจะได้รับค่า Err ทำให้เธรดแม่ตรวจพบความล้มเหลวได้
use std::thread;
fn main() {
let h = thread::spawn(|| {
panic!("boom");
});
let result = h.join();
println!("joined, is_err = {}", result.is_err());
}ข้อมูลเธรดปัจจุบัน
คุณสามารถตรวจสอบเธรดที่กำลังทำงานอยู่ด้วย thread::current ซึ่งคืนค่าตัวจัดการที่เมธอด name ใช้ดูชื่อเธรด (ถ้ามี)
เธรดหลักก็เป็นเธรดจริงเช่นกัน และโดยทั่วไปมีชื่อว่า main
use std::thread;
fn main() {
let current = thread::current();
println!("name: {:?}", current.name());
}การคืนค่าจากเธรด
คลอเชอร์ที่ส่งให้ spawn สามารถคืนค่าได้ ค่านั้นจะถูกห่อไว้ใน Ok เมื่อคุณเรียก join
นี่เป็นวิธีง่าย ๆ ในการคำนวณบางอย่างบนเธรดอื่น แล้วอ่านผลลัพธ์ในภายหลัง
use std::thread;
fn main() {
let h = thread::spawn(|| {
let sum: i32 = (1..=10).sum();
sum
});
let total = h.join().unwrap();
println!("total = {}", total);
}ตรวจสอบความเข้าใจ
ทดสอบความเข้าใจของคุณเกี่ยวกับการสร้างเธรด
สรุปทบทวน
คุณได้เรียนรู้การเริ่มเธรดด้วย thread::spawn และคลอเชอร์ ซึ่งคืนค่าเป็น JoinHandle
การเรียก join จะรอให้ทำงานเสร็จ และส่งต่อค่าที่คืนกลับมาหรือแพนิก เอาต์พุตระหว่างเธรดอาจสลับแทรกกันอย่างคาดเดาไม่ได้ และ Builder ช่วยให้คุณตั้งชื่อเธรดได้
ต่อไปคุณจะได้เรียนรู้วิธีย้ายข้อมูลเข้าไปในเธรดที่สร้างขึ้น
คำถามที่พบบ่อย
บทเรียน “สร้างเธรด” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “สร้างเธรด” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ 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 ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “สร้างเธรด” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Learn Rust Coding นี้ได้ไหม
ได้ บทเรียน Learn Rust Coding ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ