มัลติเธรดใน Python [พร้อมตัวอย่างการเข้ารหัส]
เผยแพร่แล้ว: 2020-11-30การปรับปรุงและทำให้โค้ดเร็วขึ้นเป็นขั้นตอนต่อไปหลังจากได้รับความรู้พื้นฐานของ Python มัลติเธรดดิ้งเป็นวิธีหนึ่งในการเพิ่มประสิทธิภาพนั้นโดยใช้ “เธรด” กระทู้เหล่านี้คืออะไร? และสิ่งเหล่านี้แตกต่างจากกระบวนการอย่างไร? ลองหากัน
ในตอนท้ายของบทช่วยสอนนี้ คุณจะมีความรู้ดังต่อไปนี้:
- เธรดและกระบวนการคืออะไร
- Multithreading สำเร็จได้อย่างไร?
- ข้อจำกัดของมันคืออะไร?
- เมื่อใดควรใช้มัลติเธรด
เรียนรู้ หลักสูตรวิทยาศาสตร์ข้อมูลออนไลน์ จากมหาวิทยาลัยชั้นนำของโลก รับโปรแกรม PG สำหรับผู้บริหาร โปรแกรมประกาศนียบัตรขั้นสูง หรือโปรแกรมปริญญาโท เพื่อติดตามอาชีพของคุณอย่างรวดเร็ว
สารบัญ
เธรดใน Python
เมื่อเราคิดว่าการทำงานหลายอย่างพร้อมกัน เราคิดว่าการดำเนินการแบบคู่ขนาน มัลติเธรด ไม่ ดำเนินการแบบขนานอย่างเคร่งครัด เธรดสามารถถูกมองว่าเป็นเอนทิตีที่แยกจากกันของโฟลว์การดำเนินการของส่วนต่างๆ ของโปรแกรมของคุณที่ทำงานอย่างอิสระ โดยพื้นฐานแล้วเธรดจะไม่ทำงานแบบขนาน แต่ Python เปลี่ยนจากเธรดหนึ่งเป็นเธรดอื่นอย่างรวดเร็วจนดูเหมือนขนานกัน
ในทางกลับกัน โปรเซสจะขนานกันอย่างเคร่งครัดและรันบนคอร์ต่างๆ เพื่อให้ดำเนินการได้รวดเร็วยิ่งขึ้น เธรดสามารถทำงานบนโปรเซสเซอร์ต่างๆ ได้ แต่จะยังคงไม่ทำงานพร้อมกันในทางเทคนิค
และคุณกำลังคิดว่าถ้าเธรดไม่ทำงานคู่ขนานกัน แล้วจะทำให้สิ่งต่าง ๆ เร็วขึ้นได้อย่างไร คำตอบคือไม่ได้ทำให้การประมวลผลเร็วขึ้นเสมอไป มัลติเธรดนั้นใช้เฉพาะในงานที่เธรดจะทำให้การประมวลผลเร็วขึ้น
ข้อมูลทั้งหมดของเธรดมีอยู่ใน Thread Control Block(TCB ) TCB ประกอบด้วยส่วนหลักดังต่อไปนี้:
- TID ที่ไม่ซ้ำกัน – ตัวระบุเธรด
- Stack Pointer ซึ่ง ชี้ไปที่สแต็กของเธรดในกระบวนการ
- ตัวนับโปรแกรมที่เก็บที่อยู่ของคำสั่งที่กำลังรันโดย thread
- สถานะของเธรด (ทำงาน, พร้อม, รอ, เริ่มหรือเสร็จสิ้น)
ต้องบอกว่า กระบวนการสามารถมีหลายเธรดในนั้น ซึ่งใช้รหัส ข้อมูล และไฟล์ทั้งหมดร่วมกัน และเธรดทั้งหมดมีรีจิสเตอร์และสแต็กแยกต่างหากซึ่งพวกเขาสามารถเข้าถึงได้
ตอนนี้ คุณอาจสงสัยว่าหากเธรดใช้ข้อมูลและโค้ดทั่วไป พวกเขาจะใช้งานได้อย่างไรโดยไม่ขัดขวางเธรดอื่นๆ นี่คือข้อจำกัดที่ใหญ่ที่สุดของ Multithreading ซึ่งเราจะพูดถึงในภายหลังในบทช่วยสอนนี้
การสลับบริบท
ตามที่อธิบายไว้ข้างต้น เธรดจะไม่ทำงานแบบคู่ขนาน แต่เป็นผลตามมา ดังนั้นเมื่อเธรด T1 เริ่มดำเนินการ เธรดอื่นทั้งหมดจะยังคงอยู่ในโหมดรอ หลังจาก T1 เสร็จสิ้นด้วยการดำเนินการแล้วเธรดอื่นในคิวจะเริ่มดำเนินการได้ Python เปลี่ยนจากเธรดหนึ่งเป็นเธรดอื่นอย่างรวดเร็วจนดูเหมือนการดำเนินการแบบขนาน การเปลี่ยนนี้เป็นสิ่งที่เราเรียกว่า 'การสลับบริบท'
การเขียนโปรแกรมแบบมัลติเธรด
พิจารณาโค้ดด้านล่างซึ่งใช้เธรดเพื่อดำเนินการกับคิวบ์และสแควร์
นำเข้า เกลียว def cuber (n) : พิมพ์ ( “คิวบ์: {}” .format(n * n * n)) def squarer (n) : พิมพ์ ( “สี่เหลี่ยม: {}” .format(n * n)) ถ้า __name__ == “__main__” : #สร้างกระทู้ t1 = threading.Thread(target=squarer, args=( 5 ,)) t2 = threading.Thread(target=cuber, args=( 5 ,)) #เริ่มกระทู้ t1 t1.start() #เริ่มกระทู้ t2 t2.start() #รอจนกว่าt1จะเสร็จ t1.join() #รอจนกว่าt2จะเสร็จ t2.join() #เสร็จทั้งสองกระทู้ พิมพ์ ( “เสร็จแล้ว!” ) |
#ผลลัพธ์: สแควร์: 25 ลูกบาศก์: 125 เสร็จแล้ว! |
ทีนี้มาลองทำความเข้าใจโค้ดกัน
ขั้นแรก เรานำเข้าโมดูล Threading ซึ่งรับผิดชอบงานทั้งหมด ภายใน main เราสร้าง 2 เธรดโดยสร้างคลาสย่อยของคลาสเธรด เราจำเป็นต้องส่งเป้าหมาย ซึ่งเป็นฟังก์ชันที่ต้องดำเนินการในเธรดนั้น และอาร์กิวเมนต์ที่ต้องส่งผ่านไปยังฟังก์ชันเหล่านั้น
ตอนนี้เมื่อเธรดได้รับการประกาศแล้ว เราจำเป็นต้องเริ่มต้น ทำได้โดยการเรียก วิธีการ เริ่มต้น บนเธรด เมื่อเริ่มต้นแล้ว โปรแกรมหลักต้องรอให้เธรดประมวลผลเสร็จ เราใช้ วิธี รอ เพื่อให้โปรแกรมหลักหยุดชั่วคราวและรอให้เธรด T1 และ T2 ดำเนินการเสร็จสิ้น
ต้องอ่าน: ความท้าทายของ Python สำหรับผู้เริ่มต้น
การซิงโครไนซ์เธรด
ดังที่เราได้กล่าวไว้ข้างต้น เธรดจะไม่ทำงานแบบขนาน แต่ Python จะสลับจากอันหนึ่งไปอีกอันหนึ่งแทน ดังนั้นจึงมีความจำเป็นอย่างยิ่งที่จะต้องซิงโครไนซ์อย่างถูกต้องระหว่างเธรดเพื่อหลีกเลี่ยงพฤติกรรมแปลก ๆ
สภาพการแข่งขัน
เธรดที่อยู่ภายใต้กระบวนการเดียวกันจะใช้ข้อมูลและไฟล์ทั่วไปซึ่งอาจนำไปสู่ "การแข่งขัน" สำหรับข้อมูลระหว่างหลายเธรด ดังนั้น หากหลายเธรดเข้าถึงข้อมูลบางส่วน ข้อมูลนั้นจะถูกแก้ไขโดยทั้งเธรดและผลลัพธ์ที่ได้จะไม่เป็นไปตามที่คาดไว้ สิ่งนี้เรียกว่าสภาพการแข่งขัน
ดังนั้น หากคุณมีสองเธรดที่สามารถเข้าถึงข้อมูลเดียวกันได้ ทั้งสองเธรดจะสามารถเข้าถึงและแก้ไขได้เมื่อเธรดนั้นทำงานอยู่ ดังนั้นเมื่อ T1 เริ่มดำเนินการและแก้ไขข้อมูลบางส่วน T2 จะอยู่ในโหมดสลีป/รอ จากนั้น T1 จะหยุดดำเนินการและเข้าสู่โหมดสลีปโดยมอบการควบคุมให้กับ T2 ซึ่งมีสิทธิ์เข้าถึงข้อมูลเดียวกันด้วย ดังนั้น T2 จะแก้ไขและเขียนทับข้อมูลเดิมซึ่งจะนำไปสู่ปัญหาเมื่อ T1 เริ่มต้นอีกครั้ง

จุดมุ่งหมายของการ ซิงโครไนซ์เธรด คือเพื่อให้แน่ใจว่าไม่มีเงื่อนไขการแข่งขันนี้ และส่วนสำคัญของรหัสจะเข้าถึงได้ทีละเธรดในลักษณะที่ซิงโครไนซ์
ล็อค
เพื่อแก้ปัญหาและป้องกัน Race Condition และผลที่ตามมา โมดูลเธรดมี คลาส Lock ซึ่งใช้ Semaphores เพื่อช่วยให้เธรดซิงโครไนซ์ สัญญาณไม่ได้เป็นอะไรนอกจากแฟล็กไบนารี ให้ถือว่าเป็นป้าย “หมั้น” บนตู้โทรศัพท์ที่มีค่าเป็น “หมั้น” (เท่ากับ 1) หรือ “ไม่หมั้น” (เท่ากับ 0) ดังนั้นทุกครั้งที่เธรดพบส่วนของรหัสที่มีการล็อก จะต้องตรวจสอบว่าการล็อกอยู่ในสถานะ 1 อยู่แล้วหรือไม่ ถ้าใช่ก็ต้องรอให้กลายเป็น 0 ก่อนถึงจะใช้ได้
คลาส Lock มีสองวิธีหลัก:
- earn([blocking]) : วิธี การ รับ ใช้พารามิเตอร์ บล็อก เป็น True หรือ False หากการล็อกสำหรับเธรด T1 เริ่มต้นด้วยการบล็อกเป็น True การล็อกจะรอหรือยังคงถูกบล็อกอยู่จนกว่าส่วนสำคัญของโค้ดจะถูกล็อกโดยเธรด T2 อื่น เมื่อเธรดอื่น T2 ปลดล็อค เธรด T1 จะได้รับล็อกและคืน ค่า True
ในทางกลับกัน หากการล็อกสำหรับเธรด T1 เริ่มต้นด้วยการบล็อกพารามิเตอร์เป็น False เธรด T1 จะไม่รอหรือยังคงถูกบล็อกหากส่วนสำคัญถูกล็อกโดยเธรด T2 แล้ว หากเห็นว่าล็อค มันจะคืนค่าเป็นเท็จทันทีและออก อย่างไรก็ตาม หากรหัสไม่ถูกล็อคโดยเธรดอื่น รหัสจะถูกล็อคและคืนค่า เป็น True
release() : เมื่อเรียกใช้วิธีการปลดล็อค มันจะปลดล็อคการล็อคและคืนค่า True นอกจากนี้ยังจะตรวจสอบว่ามีเธรดใดที่รอให้ปลดล็อคหรือไม่ หากมีก็จะอนุญาตให้หนึ่งในนั้นเข้าถึงล็อคได้
อย่างไรก็ตาม หากปลดล็อกแล้ว ThreadError จะปรากฏขึ้น
การหยุดชะงัก
ปัญหาอีกประการหนึ่งที่เกิดขึ้นเมื่อเราจัดการกับการล็อคหลายครั้งคือ – Deadlocks การชะงักงันเกิดขึ้นเมื่อการล็อกไม่ถูกปล่อยโดยเธรดเนื่องจากสาเหตุหลายประการ ลองพิจารณาตัวอย่างง่ายๆ ที่เราดำเนินการดังต่อไปนี้:
นำเข้า เกลียว l = threading.Lock() # ก่อนซื้อครั้งแรก ล. รับ () # ก่อนซื้อครั้งที่ 2 ล. รับ () #ตอนนี้ได้รับล็อคสองครั้ง |
ในโค้ดด้านบนนี้ เราเรียกเมธอดการได้มาสองครั้งแต่อย่าปล่อยหลังจากที่ได้มาเป็นครั้งแรก ดังนั้น เมื่อ Python เห็นคำสั่ง buy ครั้งที่สอง มันจะเข้าสู่โหมดรออย่างไม่มีกำหนด เนื่องจากเราไม่เคยปลดล็อคก่อนหน้านี้
เงื่อนไขการชะงักงันเหล่านี้อาจเล็ดลอดเข้ามาในโค้ดของคุณโดยที่คุณไม่รู้ตัว แม้ว่าคุณจะรวมการโทรออก รหัสของคุณอาจล้มเหลวระหว่างทางและจะไม่มีการโทรออกและล็อกจะยังล็อกอยู่ วิธีหนึ่งที่จะเอาชนะสิ่งนี้ได้คือการใช้ คำสั่ง with – หรือ ที่ เรียกว่า Context Managers การใช้ คำสั่ง with – เป็น คำสั่ง การล็อกจะถูกปล่อยโดยอัตโนมัติเมื่อการประมวลผลสิ้นสุดหรือล้มเหลวเนื่องจากสาเหตุใดก็ตาม
อ่าน: แนวคิดและหัวข้อโครงการ Python
ก่อนที่คุณจะไป
ดังที่เราได้กล่าวไว้ก่อนหน้านี้ Multithreading นั้นไม่มีประโยชน์ในทุกแอปพลิเคชัน เนื่องจากไม่ได้ทำให้สิ่งต่าง ๆ ทำงานแบบคู่ขนานกันจริงๆ แต่แอปพลิเคชันหลักของ Multithreading คือระหว่างงาน I/O ซึ่ง CPU จะอยู่เฉยๆ ขณะรอการโหลดข้อมูล Multithreading มีบทบาทสำคัญที่นี่เนื่องจากเวลาว่างของ CPU นี้ถูกใช้ในงานอื่นๆ จึงเหมาะอย่างยิ่งสำหรับการเพิ่มประสิทธิภาพ
หากคุณอยากเรียนรู้เกี่ยวกับวิทยาศาสตร์ข้อมูล ลองดู โปรแกรม Executive PG ของ IIIT-B & upGrad ใน Data Science ซึ่งสร้างขึ้นสำหรับมืออาชีพที่ทำงานและมีกรณีศึกษาและโครงการมากกว่า 10 รายการ เวิร์กช็อปภาคปฏิบัติจริง การให้คำปรึกษากับผู้เชี่ยวชาญในอุตสาหกรรม 1 -on-1 พร้อมที่ปรึกษาในอุตสาหกรรม การเรียนรู้มากกว่า 400 ชั่วโมงและความช่วยเหลือด้านงานกับบริษัทชั้นนำ
เธรดใน Python คืออะไร
เธรดเป็นเอนทิตีภายในกระบวนการที่อาจกำหนดเวลาสำหรับการดำเนินการใน Python ในแง่ของฆราวาส เธรดคือกระบวนการคำนวณที่ดำเนินการโดยคอมพิวเตอร์ เป็นชุดของคำสั่งดังกล่าวภายในโปรแกรมที่นักพัฒนาอาจเรียกใช้โดยไม่ขึ้นกับสคริปต์อื่น เธรดช่วยให้คุณเพิ่มความเร็วของแอปพลิเคชันโดยใช้ความเท่าเทียมกัน เป็นกระบวนการที่มีน้ำหนักเบาซึ่งจะช่วยให้งานต่างๆ ทำงานควบคู่กันไปได้ เธรดทำงานอย่างอิสระและใช้งาน CPU ได้สูงสุด ดังนั้นจึงช่วยปรับปรุงประสิทธิภาพของ CPU
การใช้ multi-thread ใน Python คืออะไร?
มัลติเธรดดิ้งเป็นเทคนิคการทำเธรดในการเขียนโปรแกรม Python ที่ช่วยให้เธรดจำนวนมากทำงานพร้อมกันโดยการสลับระหว่างเธรดอย่างรวดเร็วด้วยความช่วยเหลือของ CPU (เรียกว่าการสลับบริบท) เมื่อเราสามารถแบ่งงานของเราออกเป็นหลายๆ ส่วนแยกกันได้ เราจะใช้มัลติเธรด ตัวอย่างเช่น สมมติว่าคุณต้องดำเนินการสืบค้นฐานข้อมูลที่ซับซ้อนเพื่อรับข้อมูลและแยกการสืบค้นออกเป็นข้อความค้นหาแต่ละรายการจำนวนมาก ในกรณีนั้น จะเป็นการดีกว่าที่จะจัดสรรเธรดให้กับแต่ละคิวรีและเรียกใช้ทั้งหมดพร้อมกัน
การซิงโครไนซ์เธรดคืออะไร?
การซิงโครไนซ์เธรดได้รับการอธิบายว่าเป็นวิธีการที่รับประกันว่ากระบวนการหรือเธรดที่เกิดขึ้นพร้อมกันตั้งแต่สองรายการขึ้นไปไม่ได้ดำเนินการส่วนสำคัญของโปรแกรมพร้อมกัน วิธีการซิงโครไนซ์ใช้เพื่อควบคุมการเข้าถึงกระบวนการไปยังส่วนที่สำคัญ เมื่อเราเริ่มต้นสองเธรดขึ้นไปภายในโปรแกรม มีโอกาสที่หลายเธรดอาจพยายามเข้าถึงทรัพยากรเดียวกัน ส่งผลให้เกิดผลลัพธ์ที่ไม่คาดคิดเนื่องจากความท้าทายในการทำงานพร้อมกัน ตัวอย่างเช่น หากเธรดจำนวนมากพยายามเขียนภายในไฟล์เดียวกัน ข้อมูลอาจเสียหายเนื่องจากหนึ่งในเธรดสามารถแทนที่ข้อมูล หรือเมื่อเธรดหนึ่งกำลังเปิดและอีกเธรดหนึ่งกำลังปิดไฟล์เดียวกัน