เธรด
การทำงานพร้อมกัน
เธรด เป็นบทเรียน Ruby Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Ruby Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Ruby Academy มีบทเรียนทั้งหมด 4 บทเรียน
เธรดคืออะไร
เธรดคือเส้นทางการทำงานที่เป็นอิสระภายในโปรแกรมของคุณ Ruby ช่วยให้คุณทำงานหลายเธรดได้ เพื่อให้งานเหล่านั้นดำเนินไปคาบเกี่ยวกันตามเวลา
- โปรแกรมหลักทำงานอยู่ในเธรดหลัก
- คุณสร้างเธรดเพิ่มได้ด้วย
Thread.new - เธรดใช้หน่วยความจำร่วมกัน จึงสามารถอ่านและเขียนตัวแปรเดียวกันได้
เธรดเหมาะอย่างยิ่งเมื่อโปรแกรมใช้เวลาไปกับการรอ (เครือข่าย ดิสก์ การหยุดพัก) เพราะเธรดหนึ่งสามารถรอ ขณะที่อีกเธรดยังคงทำงานต่อได้
การสร้างเธรด
ส่งบล็อกให้ Thread.new บล็อกนั้นจะทำงานในเธรดใหม่ เรียก join เพื่อรอให้ทำงานเสร็จก่อนที่โปรแกรมจะจบ
t = Thread.new do
puts "Hello from the new thread"
end
t.join
puts "Main thread done"เหตุใด join จึงสำคัญ
เมื่อเธรดหลักจบการทำงาน Ruby จะจบการทำงานด้วย และอาจไม่รอเธรดอื่น join จะหยุดผู้เรียกไว้จนกว่าเธรดเป้าหมายจะทำงานเสร็จ
หากไม่มี join เธรดงานอาจไม่มีโอกาสพิมพ์ผลลัพธ์ก่อนที่โปรแกรมจะปิดลง
t = Thread.new do
sleep 0.1
puts "Worker finished"
end
puts "Waiting..."
t.join
puts "All done"หลายเธรดพร้อมกัน
คุณสามารถเริ่มกลุ่มเธรด เก็บเธรดเหล่านั้นไว้ในอาร์เรย์ แล้วเรียก join กับเธรดแต่ละตัว (each) ได้ นี่เป็นรูปแบบที่ใช้กันทั่วไปสำหรับงานรับส่งข้อมูลที่ทำงานคล้ายขนาน
threads = (1..3).map do |n|
Thread.new do
puts "Thread number " + n.to_s
end
end
threads.each(&:join)
puts "Finished all threads"การใช้ตัวแปรร่วมกัน
เธรดใช้หน่วยความจำร่วมกัน ตัวแปรที่กำหนดไว้ก่อนสร้างเธรดจะมองเห็นได้จากภายในเธรดนั้น วิธีนี้มีประโยชน์มาก แต่ก็อันตรายเช่นกันหากเธรดสองตัวเขียนค่าเดียวกัน
counter = 0
t = Thread.new do
counter += 1
end
t.join
puts "Counter is " + counter.to_sภาวะการแข่งขัน
ภาวะการแข่งขันเกิดขึ้นเมื่อเธรดสลับการอัปเดตข้อมูลที่ใช้ร่วมกัน และผลลัพธ์ขึ้นอยู่กับจังหวะเวลา
counter += 1แท้จริงแล้วประกอบด้วยการอ่าน การบวก และการเขียน- เธรดสองตัวอาจอ่านค่าเดิมเดียวกัน แล้วเขียนค่าใหม่เดียวกัน ทำให้การเพิ่มค่าครั้งหนึ่งสูญหายไป
วิธีแก้คือประสานการเข้าถึงด้วยล็อก
มิวเท็กซ์: ล็อก
Mutex (การไม่ให้เข้าถึงพร้อมกัน) รับรองว่าจะมีเธรดเพียงตัวเดียวที่ทำงานในโค้ดที่ป้องกันไว้ในแต่ละครั้ง ให้ครอบส่วนวิกฤตด้วย mutex.synchronize
mutex = Mutex.new
counter = 0
threads = (1..5).map do
Thread.new do
mutex.synchronize do
counter += 1
end
end
end
threads.each(&:join)
puts "Counter is " + counter.to_sการคืนค่า
Thread#value จะรอให้เธรดทำงานเสร็จ แล้วคืนค่าที่บล็อกส่งกลับมา ซึ่งเทียบได้กับการทำ join โดยอัตโนมัติพร้อมกับคืนผลลัพธ์
t = Thread.new do
2 + 3
end
puts "Result is " + t.value.to_sตัวแปรเฉพาะเธรด
เธรดแต่ละตัวสามารถเก็บค่าของตัวเองโดยใช้สัญลักษณ์เป็นคีย์ผ่าน Thread.current[:key] ค่าเหล่านี้เป็นข้อมูลเฉพาะของเธรดนั้นและไม่ถูกใช้ร่วมกัน
t = Thread.new do
Thread.current[:name] = "worker"
puts "Inside: " + Thread.current[:name]
end
t.joinการจัดการข้อยกเว้น
หากเธรดทำให้เกิดข้อผิดพลาด ข้อผิดพลาดนั้นจะยังไม่แสดงจนกว่าคุณจะเรียก join หรือ value ซึ่งจะทำให้ข้อผิดพลาดถูกส่งขึ้นมาอีกครั้ง การตั้งค่า Thread.abort_on_exception = true จะทำให้ข้อผิดพลาดทำให้โปรแกรมทั้งหมดหยุดทำงานทันที ซึ่งช่วยในการแก้ไขข้อผิดพลาด
t = Thread.new do
raise "boom"
end
begin
t.join
rescue => e
puts "Caught: " + e.message
endเธรดช่วยเมื่อใด
เธรดเหมาะมากกับงานที่ผูกกับการรับส่งข้อมูล ซึ่งใช้เวลาไปกับการรอ เธรดช่วยได้น้อยกว่าสำหรับงานที่ผูกกับ CPU เนื่องจาก GVL (เราจะกล่าวถึงในหัวข้อถัดไป)
- เหมาะ: ดาวน์โหลดที่อยู่เว็บจำนวนมาก อ่านไฟล์จำนวนมาก
- มีข้อจำกัด: การคำนวณตัวเลขจำนวนมากแบบ heavy บนหลายคอร์
ปกป้องสถานะที่เปลี่ยนแปลงร่วมกันด้วย Mutex เสมอ
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจของคุณเกี่ยวกับเธรด
ทบทวน: เธรด
คุณได้เรียนรู้หลักสำคัญของเธรดใน Ruby ดังนี้
Thread.newเริ่มการทำงานแบบสอดประสานjoinใช้รอ ส่วนvalueใช้รอและคืนผลลัพธ์- เธรดใช้หน่วยความจำร่วมกัน จึงทำให้เกิดภาวะการแข่งขัน
Mutexที่ใช้ร่วมกับsynchronizeจะปกป้องสถานะที่ใช้ร่วมกัน- เธรดเหมาะอย่างยิ่งกับงานที่ผูกกับการรับส่งข้อมูล
ต่อไปเราจะสำรวจว่าเหตุใดเธรดจึงใช้หลายคอร์ของ CPU ได้ไม่เต็มที่ นั่นคือ GVL
คำถามที่พบบ่อย
บทเรียน “เธรด” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “เธรด” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Ruby Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Ruby Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “เธรด”
การทำงานพร้อมกัน คุณปฏิบัติ Ruby Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Ruby Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Ruby Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “เธรด” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Ruby Academy นี้ได้ไหม
ได้ บทเรียน Ruby Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ