อะไรคือการใช้เธรดในการเขียนโปรแกรมอย่างเหมาะสม?


13

ฉันเบื่อที่จะได้ยินคนแนะนำว่าคุณควรใช้เพียงหนึ่งเธรดต่อโปรเซสเซอร์ในขณะที่หลาย ๆ โปรแกรมใช้มากถึง 100 ต่อกระบวนการ! ยกตัวอย่างบางโปรแกรมทั่วไป

vb.net ide uses about 25 thread when not debugging
System uses about 100
chrome uses about 19
Avira uses more than about 50

ทุกครั้งที่ฉันโพสต์คำถามที่เกี่ยวข้องกับเธรดฉันได้รับการเตือนเกือบทุกครั้งที่ฉันไม่ควรใช้มากกว่าหนึ่งเธรดต่อตัวประมวลผลและโปรแกรมทั้งหมดที่ฉันพูดถึงข้างต้นจะทำลายระบบของฉันด้วยโปรเซสเซอร์เดียว


7
คำแนะนำนั้นกว้างมาก ขีด จำกัด ของหนึ่งเธรดต่อตัวประมวลผลนั้นเหมาะสมสำหรับแอปพลิเคชันที่ผูกเข้ากับการคำนวณเท่านั้น โปรแกรมส่วนใหญ่มีการเชื่อมต่อกับ IO ไม่ว่าจะเป็นปริมาณการใช้งานเครือข่ายการเข้าถึงดิสก์หรือแม้แต่ RAM นั่นเป็นสาเหตุที่เว็บเซิร์ฟเวอร์ฐานข้อมูล ฯลฯ มีเธรดพูลต์ที่มีจำนวนเธรดมากกว่าตัวประมวลผลหลัก
Kilian Foth

2
"ฉันถูกเตือนเกือบทุกครั้งที่ไม่ควรใช้มากกว่าหนึ่งเธรดต่อโปรเซสเซอร์" คุณสามารถโพสต์ลิงก์หรือตัวอย่างได้หรือไม่? เกือบทุกครั้งเหรอ
S.Lott

2
"... ผู้คนแนะนำว่าคุณควรใช้เพียงหนึ่งเธรดต่อกระบวนการ" ใครคือคนเหล่านี้ การจัดตารางเวลามีความก้าวหน้าอย่างมากตั้งแต่ยุคมืด
Rein Henrichs

2
คุณไม่ควรมีมากกว่าหนึ่งเธรด UIต่อกระบวนการ
slaks

3
@Billy ONeal การแก้ไขของคุณทำให้คำถามไม่มีความหมาย
SK-logic

คำตอบ:


22

คุณควรใช้เพียงหนึ่งเธรดต่อตัวประมวลผล

อาจเป็นไปได้ใน HPC ที่คุณต้องการประสิทธิภาพสูงสุด - แต่อย่างอื่นที่ฉันเคยได้ยินวันนี้โง่!

คุณควรใช้จำนวนเธรดที่เหมาะสมกับการออกแบบของโปรแกรมและยังให้ประสิทธิภาพที่ยอมรับได้

สำหรับเว็บเซิร์ฟเวอร์อาจเหมาะสมที่จะเริ่มการทำงานของเธรดสำหรับการเชื่อมต่อขาเข้าแต่ละครั้ง (แม้ว่าจะมีวิธีที่ดีกว่าสำหรับเซิร์ฟเวอร์ที่โหลดหนักมาก)

สำหรับ IDE แต่ละเครื่องมือที่ทำงานในเธรดของตัวเองจะไม่มีเหตุผล ฉันสงสัยว่าหลายเธรดที่รายงานสำหรับ. NET IDE คือสิ่งต่าง ๆ เช่นการบันทึกและงาน I / O ที่เริ่มต้นในเธรดของตนเองเพื่อให้สามารถยกเลิกการบล็อกได้


9
ตอนนี้คุณทำให้ฉันสงสัยว่าสิ่งที่โง่ที่สุดที่คุณเคยได้ยินคืออะไร!
Michael K

3
@Michael - ฉันได้สอนนักศึกษาระดับปริญญาตรีและทำงานเกี่ยวกับสัญญาป้องกัน - คุณจะไม่เชื่อในสิ่งที่โง่ที่สุดที่ฉันเคยได้ยิน!
Martin Beckett

1
เราเคยเห็นพวกเขาใน TheDailyWTF.com หรือไม่
FrustratedWithFormsDesigner

ฉันไม่สามารถหาพวกเขาตอนนี้จริงๆ แต่ดูที่ลิงค์นี้social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/…
สมิ ธ

2
ได้ที่มากที่สุดด้าย CPU ผูกพันต่อหนึ่งหน่วยประมวลผลที่จัดสรรให้กับแอพลิเคชัน เธรดที่มีขอบเขต IO ไม่ใช่ปัญหาใหญ่ (นอกเหนือจากหน่วยความจำที่ใช้) และสิ่งสำคัญที่ต้องจำไว้ว่าแอปสามารถถูก จำกัด ให้ใช้ชุดย่อยของซีพียูของระบบเท่านั้น ท้ายที่สุดมัน (โดยปกติ) คอมพิวเตอร์ของผู้ใช้ / ผู้ดูแลระบบและไม่ใช่ของโปรแกรมเมอร์
Donal Fellows

2

คำแนะนำแบบหนึ่งเธรดต่อคอร์จะถูกนำไปใช้เมื่อวัตถุประสงค์คือความเร็วผ่านการดำเนินการแบบขนาน

เหตุผลที่แตกต่างอย่างสมบูรณ์และถูกต้องเท่าเทียมกันคือความเรียบง่ายของรหัสเมื่อมีการตอบสนองต่อเหตุการณ์ที่ไม่สามารถคาดการณ์ได้ ดังนั้นหากโปรแกรมต้องฟังซ็อกเก็ต 100 ซ็อตและดูเหมือนจะให้ความสนใจกับแต่ละซ็อกเก็ตอย่างเต็มที่นั่นเป็นการใช้งานที่สมบูรณ์แบบสำหรับการทำเกลียว อีกตัวอย่างหนึ่งคือ UI ที่เธรดหนึ่งจัดการกิจกรรม UI ในขณะที่อีกเธรดกำลังประมวลผลพื้นหลัง


1
การประมวลผลแบบ จำกัด ขอบเขต IO สามารถทำได้เป็นหนึ่งเธรดต่อแหล่งเหตุการณ์หรือหลายแหล่งเหตุการณ์สามารถมัลติเพล็กซ์ลงบนเธรดเดี่ยว รหัสมัลติเพล็กซ์นั้นมักจะซับซ้อนและมีประสิทธิภาพมากกว่า
Donal Fellows

2

คุณต้องการหนึ่งเธรดสำหรับแต่ละการคำนวณซึ่งสามารถดำเนินการในอัตราที่แตกต่างจากการคำนวณอื่น ๆ

สำหรับการคำนวณแบบ CPU-bound แบบขนานซึ่งมาในบล็อคการทำงานขนาดใหญ่โดยทั่วไปคุณต้องการหนึ่งเธรดต่อ CPU เพราะเมื่อมันยุ่งทั้งหมดเธรดเพิ่มเติมจะไม่ช่วยและสร้างค่าใช้จ่ายของตัวจัดกำหนดการ หากบล็อกของงานมีขนาดไม่ตรงเวลาหรือถูกสร้างแบบไดนามิก ณ รันไทม์ (มักเกิดขึ้นเมื่อคุณมีโครงสร้างข้อมูลขนาดใหญ่ที่ซับซ้อนในการประมวลผล) คุณอาจต้องการแนบบล็อกเหล่านั้นกับเธรดจำนวนมากดังนั้นตัวจัดตารางจะมีขนาดใหญ่เสมอ ตั้งค่าให้เลือกเมื่อบล็อกบางส่วนทำงานเสร็จสมบูรณ์เพื่อให้ CPUs ทั้งหมดไม่ว่าง

สำหรับการคำนวณ I / O ที่ผูกไว้โดยทั่วไปคุณต้องการหนึ่งเธรดสำหรับแต่ละ I / O อิสระ "ช่อง" เนื่องจากพวกเขาสื่อสารด้วยอัตราที่แตกต่างกันและเธรดที่ถูกบล็อกในช่องนั้นไม่ป้องกันกระทู้อื่น ๆ สำหรับความคืบหน้า


เพิ่งทราบว่าการทำเกลียวในลักษณะนี้สามารถนำไปสู่บางโปรแกรมที่ออกแบบมาอย่างแปลกประหลาด ฉันได้เห็นโปรแกรม 4 เธรดที่มีเธรดเพื่ออ่านเร็กคอร์ดจากตาราง DB, เธรดเพื่อเขียนเร็กคอร์ดที่แปลงแล้วไปยังซ็อกเก็ต, เธรดเพื่ออ่านคำตอบสำหรับซ็อกเก็ตเหล่านั้นเขียน (ซึ่งกลับมาออกคำสั่ง และแบบอะซิงโครนัส) และเธรดเพื่อแก้ไขระเบียนฐานข้อมูลต้นฉบับด้วยคำตอบ เงื่อนไขข้อผิดพลาดที่ไม่เข้าใจง่ายเกิดขึ้น
Bruce Ediger

มุมมองหนึ่งคือรูปแบบนี้สร้างโปรแกรมที่แปลก อีกมุมมองหนึ่งคือลักษณะที่เป็นธรรมชาติที่โปรแกรมควรมี Dunno เกี่ยวกับเงื่อนไขข้อผิดพลาด "ไม่ได้ใช้งาน"; หากคุณมีหลายสิ่งที่เกิดขึ้นและหนึ่งในนั้นได้รับข้อผิดพลาดตรวจสอบให้แน่ใจว่ามีการแพร่กระจายอย่างถูกต้องในการคำนวณแบบอะซิงโครนัสเป็นปัญหาสำหรับ langauges จำนวนมาก [อย่างน่าประหลาดใจ ปัญหาเกี่ยวกับรูปแบบโปรแกรม (การเขียนโปรแกรม PARLANSE ของเรามีคำว่า [ดูประวัติของฉัน] จัดการข้อยกเว้นข้ามขอบเขตของเธรดอย่างหมดจดดังนั้นจึงเป็นไปได้ที่จะทำสิ่งนี้ได้)
Ira Baxter

1

กฎของหัวแม่มือสำหรับเธรดคือคุณต้องการอย่างน้อยหนึ่ง "แอคทีฟ" (สามารถให้คำสั่งดำเนินการกับเวลา CPU ในทันที) เธรดของผู้ปฏิบัติงานสำหรับแต่ละ "ยูนิตการเรียกใช้งาน" ที่มีอยู่ในคอมพิวเตอร์ "หน่วยการดำเนินการ" เป็นหนึ่งหน่วยประมวลผลคำสั่งแบบโลจิคัลดังนั้นเซิร์ฟเวอร์ Xth hyperthreaded แบบ quad-chip, quad-core Xeon จะมี 32 EUs (4 ชิป, 4 คอร์ต่อชิปแต่ละไฮเปอร์เธรด) Core i7 เฉลี่ยของคุณจะมี 8

หนึ่งเธรดต่อ EU คือการใช้พลังงานของ CPU อย่างเต็มที่โดยที่เธรดจะอยู่ในสถานะใช้งานอยู่เสมอ นี่เป็นกรณีที่แทบไม่เคยเกิดขึ้นเนื่องจากเธรดต้องการการเข้าถึงหน่วยความจำที่ไม่ใช่แคชฮาร์ดดิสก์พอร์ตเครือข่ายและอื่น ๆ ที่ต้องรอและไม่ต้องใช้ CPU ในการดำเนินการ คุณสามารถเพิ่มประสิทธิภาพโดยรวมได้มากขึ้นด้วยการเพิ่มจำนวนเธรดที่มากขึ้น สิ่งนี้มีค่าใช้จ่าย เมื่อ CPU สลับเธรดมันจะต้องแคชรีจิสเตอร์ของเธรดตัวชี้การเรียกใช้งานและข้อมูลสถานะอื่น ๆ ตามปกติที่เก็บไว้ในการทำงานด้านในสุดของ EU และเข้าถึงได้อย่างรวดเร็วทำให้ EU อื่น ๆ ในชิป CPU นั้นหยิบขึ้นมา นอกจากนี้ยังต้องการเธรดในระบบปฏิบัติการเพื่อตัดสินใจว่าควรเปลี่ยนเธรดใด สุดท้ายเมื่อสหภาพยุโรปสลับเธรด มันสูญเสียประสิทธิภาพที่เพิ่มขึ้นของไพพ์ไลน์ที่สถาปัตยกรรมโปรเซสเซอร์ส่วนใหญ่ใช้ มันต้องล้างไปป์ไลน์ก่อนที่จะสลับเธรด แต่เนื่องจากทั้งหมดนี้ยังคงใช้เวลาโดยเฉลี่ยน้อยกว่าเพียงแค่รอฮาร์ดไดรฟ์หรือแม้แต่แรมกลับมาพร้อมข้อมูลจึงคุ้มค่ากับราคา

อย่างไรก็ตามโดยทั่วไปเมื่อคุณมีจำนวนเธรด "แอ็คทีฟ" เกินสองเท่าในสหภาพยุโรประบบปฏิบัติการจะเริ่มใช้เธรดการกำหนดเวลาตามเวลาของ EU มากขึ้นและสหภาพยุโรปใช้เวลาสลับกันระหว่างเธรดมากกว่าจะใช้เธรดแอ็คทีฟจริง ของโปรแกรม นี่คือจุดของการไม่เคารพต่อขนาด จริง ๆ แล้วจะใช้เวลานานกว่าสำหรับอัลกอริทึมแบบมัลติเธรดที่จะเรียกใช้ถ้าคุณต้องการเพิ่มเธรดพิเศษ ณ จุดนี้

ดังนั้นโดยรวมคุณต้องการรักษาเธรดจำนวนมากในโปรแกรมของคุณอย่างน้อยที่สุดเท่าที่คุณมี EUs บนเครื่องคอมพิวเตอร์ แต่คุณต้องการหลีกเลี่ยงการมีจำนวนมากกว่าสองเท่าของจำนวนที่ไม่รอหรือนอนหลับ


ถ้า N คือจำนวนของเธรดและ U คือจำนวนของหน่วย OP จะถามกฎ "N = U" คุณกำลังผ่อนคลายด้วยกฎ "U <= N <= 2 U" ฉันจะไปอีกหน่อยแล้วบอกว่า "N <= c U" สำหรับค่าคงที่ "มีขนาดเล็กพอสมควร" (รู้จักกับโปรแกรมเมอร์) c เป็นที่ยอมรับได้ (ถ้ามาตรฐานแสดงประสิทธิภาพที่สมเหตุสมผล) ฉันจะกังวลมากถ้าจำนวนกระทู้สามารถเติบโตเป็นจำนวนไม่ จำกัด
5gon12eder

1

คุณควรใช้หนึ่งเธรดสำหรับ:

โปรเซสเซอร์แต่ละตัวที่คุณต้องยุ่งอยู่เสมอ

I / O แต่ละรายการคุณสามารถใช้งานพร้อมกันได้อย่างเป็นประโยชน์โดยที่คุณไม่สามารถดำเนินการในแบบที่ไม่มีการบล็อกได้ (ตัวอย่างเช่นอ่านจากดิสก์ภายในเครื่อง)

แต่ละงานที่ต้องใช้เธรดเฉพาะเช่นการโทรเข้าไปในไลบรารีที่ไม่มีส่วนต่อประสานที่ไม่ปิดกั้นหรือส่วนต่อประสานที่ไม่ได้ปิดกั้นไม่เหมาะสม ซึ่งรวมถึงงานต่าง ๆ เช่นการตรวจสอบนาฬิการะบบตัวจับเวลาการยิงและอื่น ๆ

เพิ่มอีกเล็กน้อยเพื่อป้องกันการบล็อกที่ไม่คาดคิดเช่นข้อบกพร่องของหน้า

เพิ่มอีกเล็กน้อยเพื่อป้องกันการบล็อกที่คาดไว้ซึ่งไม่คุ้มค่ากับการปรับให้เหมาะสมตัวอย่างเช่นในโค้ดที่ไม่สำคัญ (ตัวอย่างเช่นถ้าคุณอาจไม่ค่อยต้องการทำ DNS คำขอมันอาจไม่คุ้มค่าที่จะทำคำร้องขอ DNS แบบอะซิงโครนัสเพียงแค่สร้างหัวข้อเพิ่มเติมสองสามข้อและทำให้ชีวิตของคุณง่ายขึ้น)

หากคุณปฏิบัติตามกฎ "หนึ่งเธรดต่อตัวประมวลผล" รหัสของคุณทั้งหมดนั้นมีความสำคัญอย่างยิ่งต่อประสิทธิภาพ รหัสใด ๆ ที่บล็อกด้วยเหตุผลบางอย่างหมายความว่ากระบวนการของคุณไม่สามารถใช้โปรเซสเซอร์นั้นได้ ทำให้การเขียนโปรแกรมยากขึ้นมากโดยไม่มีเหตุผลที่ดี


0

คุณสามารถวางไข่กระบวนการและเธรดเพื่อเปิดใช้งานการใช้ระบบมัลติคอร์ \ มัลติโปรเซสเซอร์สำหรับโปรแกรมเดียวซึ่งในกรณีที่คุณไม่ได้รับประโยชน์

หรือคุณสามารถมีกิจวัตรประจำวันที่โพลสำหรับเหตุการณ์ซึ่งโดยทั่วไปจะบล็อกการดำเนินการเพิ่มเติม จากนั้นผูก CPU กับการสำรวจคุณสามารถสร้างเธรดที่จะอยู่ในสถานะว่างจนกว่าเหตุการณ์ที่เหมาะสมจะเกิดขึ้น วิธีนี้ใช้กันอย่างแพร่หลายในเว็บเซิร์ฟเวอร์และ GUI เหตุการณ์คิว โปรแกรมส่วนใหญ่ต้องการให้มีแหล่งข้อมูลส่วนกลาง (แม้ว่ารหัสการทำงานของโปรแกรม) ที่เธรดทั้งหมดสามารถเข้าถึงได้ดังนั้นฉันเดาว่านั่นเป็นเหตุผลที่พวกเขาใช้เธรดเหนือกระบวนการ


0

ปพลิเคชันที่คุณกล่าวถึงไม่ค่อยจะทำงานนับทุกคนของกระทู้พร้อมกัน ที่สุดของพวกเขาเพียงแค่นั่งอยู่ที่นั่นเพราะพวกเขากำลังอยู่ในสระว่ายน้ำด้าย แอปส่งงานต่าง ๆ ไปยังคิวซึ่งถูกลบโดยเธรดในเธรดพูล

ทำไมสระว่ายน้ำถึงใหญ่มาก เนื่องจากเธรดส่วนใหญ่ต้องรอทรัพยากรอื่น ๆ เช่นดิสก์เครือข่ายผู้ใช้เธรดอื่น ๆ เป็นต้นขณะที่เธรดกำลังรออยู่จึงควรรันเธรดอื่นเพื่อใช้ประโยชน์ตัวประมวลผลอย่างเต็มที่ การปรับขนาดสระว่ายน้ำอย่างเหมาะสมนั้นค่อนข้างยุ่งยาก มีเธรดน้อยเกินไปและคุณจะสูญเสียประสิทธิภาพเนื่องจากโปรเซสเซอร์ไม่ได้ใช้อย่างเต็มที่ขณะรอบางสิ่ง มีเธรดมากเกินไปและคุณจะเสียประสิทธิภาพเนื่องจากสลับไปมาระหว่างเธรดเหล่านั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.