มัลติเธรดที่มีจำนวนเธรดจำนวนมาก

ฉันกำลังจำลองเครือข่ายแบบตาข่ายที่มีโหนดจำนวนมาก โหนดจะส่งข้อมูลระหว่างโหนดหลักต่างๆ ทั่วทั้งเครือข่าย

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

การรันสิ่งนี้บนคอมพิวเตอร์ทั่วไปที่มี 1600 โหนดส่งผลให้มี 1600 เธรด และประสิทธิภาพการทำงานแย่มาก

อะไรคือแนวทางที่ดีในการจัดการเธรดเพื่อให้แต่ละโหนดทำหน้าที่เหมือนกับว่ามันทำงานบนเธรดของตัวเอง

ในกรณีที่มีความสำคัญ ฉันกำลังสร้างการจำลองใน python 2.7 แต่ฉันก็พร้อมที่จะเปลี่ยนไปใช้อย่างอื่นถ้ามันสมเหตุสมผล


person Liron    schedule 30.09.2013    source แหล่งที่มา
comment
คุณควรพิจารณาใช้การจัดคิว (thread-) บางประเภทหรืออย่างน้อยก็มีผู้ส่งเพื่อจัดการการไหลของข้อมูล อย่างไรก็ตาม มันยากที่จะบอกโดยไม่รู้ว่าคุณต้องการทำอะไรให้สำเร็จ   -  person tamasgal    schedule 30.09.2013
comment
แน่นอนว่าการรัน 1,600 เธรดจะทำให้ประสิทธิภาพการทำงานไม่ดีในคอมพิวเตอร์ทั่วไป คุณอาจต้องพิจารณาคอมพิวเตอร์ประสิทธิภาพสูง หรือคุณสามารถลองใช้ GPU ของคุณเพื่อพลังการประมวลผลที่มากขึ้น GPU ดีสำหรับมัลติเธรด   -  person justhalf    schedule 30.09.2013
comment
@justhalf แน่นอนว่ามันจะไม่ดี แต่ละเธรดจะทำงานเพียงสองสามมิลลิวินาทีในแต่ละวินาทีและพักการทำงานของเวลาที่เหลือ ดังนั้นฉันคิดว่าปัญหาไม่ใช่ทรัพยากรของ CPU แต่เป็นจำนวนคอร์หรือเพียงแค่การมีอยู่ของเธรดจำนวนมากนั้นและบริบทจะสลับไป จำเป็นต้อง. แทนที่จะเป็น 1,600 ฉันควรจะพูดว่า 10,000 ด้วยซ้ำ ฉันกำลังมองหาวิธีแก้ปัญหาที่ดีในการประมาณโหนดเหล่านี้ที่ทำงานแบบขนานเพื่อเพิ่มจำนวนโหนดที่ฉันสามารถทำงานได้ให้สูงสุด ฉันไม่คิดว่าการย้ายไปใช้ GPU จะช่วยได้จริงๆ   -  person Liron    schedule 30.09.2013
comment
คุณหมายถึงอะไรโดยการประมาณโหนดเหล่านี้   -  person justhalf    schedule 30.09.2013
comment
การประมาณลักษณะคู่ขนานที่สมบูรณ์ การรันบน CPU ปกติทำให้ฉันไม่สามารถให้แต่ละโหนดมีเธรดเป็นของตัวเองได้ และถือว่าโหนดทั้งหมดทำงานควบคู่กันไป ตัวอย่างเช่น ฉันอาจมีเธรดควบคุมหนึ่งเธรด (หรือสองสามเธรด) ซึ่งจะเริ่มต้นเธรดขนาดเล็กเมื่อโหนดใดโหนดหนึ่งมีข้อมูลที่จะส่ง แต่โดยส่วนใหญ่แล้วจะไม่มีเธรดสำหรับแต่ละโหนด   -  person Liron    schedule 30.09.2013
comment
โปรดอ่านต่อที่ GlobalInterpreterLock   -  person Lasse V. Karlsen    schedule 30.09.2013
comment
@ LasseV.Karlsen - ฉันคิดว่าแม้การใช้ Jython ที่เปิดใช้งานหลายโหนดบน CPU จะไม่ช่วยฉันหากจำนวนเธรดเป็น 10K หรือ 100K อาจจำเป็นต้องใช้สถาปัตยกรรมอื่น (และ/หรือภาษาการใช้งาน) ที่นี่   -  person Liron    schedule 30.09.2013


คำตอบ (4)


ประการแรก คุณใช้เธรด Python เริ่มต้นปกติที่มีอยู่ในล่าม Python 2.7 เริ่มต้น (CPython) จริง ๆ หรือไม่ และโค้ดทั้งหมดของคุณเป็น Python หรือไม่ หากเป็นเช่นนั้น คุณอาจไม่ได้ใช้ CPU คอร์หลายคอร์จริงๆ เนื่องจากการล็อคล่ามส่วนกลางที่ CPython มี (ดู https://wiki.python.org/moin/GlobalInterpreterLock) คุณอาจลองรันโค้ดของคุณภายใต้ Jython เพื่อตรวจสอบว่าประสิทธิภาพดีขึ้นหรือไม่

คุณควรคิดใหม่เกี่ยวกับสถาปัตยกรรมแอปพลิเคชันของคุณและเปลี่ยนไปใช้การกำหนดเวลากิจกรรมด้วยตนเองแทนการใช้เธรด หรืออาจลองใช้บางอย่างเช่น Greenlets (https://stackoverflow.com/a/15596277/1488821) แต่นั่นอาจหมายถึงการกำหนดเวลาที่แม่นยำน้อยลงเนื่องจากขาดความขนาน

person Ivan Voras    schedule 30.09.2013
comment
ฉันใช้ python ที่มาพร้อมกับ Canopy (คิด) ฉันคิดว่านั่นเป็น CPython ปกติ - person Liron; 30.09.2013
comment
ดูจากกูเกิ้ลนิดหน่อยก็ประมาณนั้นครับ แต่อย่างที่คนอื่นๆ แนะนำไว้ ปัญหาของคุณน่าจะแก้ไขได้ดีกว่าโดยใช้สถาปัตยกรรมแอปพลิเคชันอื่น - person Ivan Voras; 01.10.2013
comment
ฉันเปลี่ยนสถาปัตยกรรมไปใช้ gevents โดยแต่ละโหนดทำงานบน greenlet ของตัวเอง สำหรับแอปพลิเคชันของฉัน สิ่งนี้ใช้งานได้ดีจริง ๆ เพราะฉันไม่ต้องการฟังก์ชันการทำงานแบบขนานจริง ๆ และการทำงานพร้อมกันก็เพียงพอแล้ว (โดยพื้นฐานแล้ว Greenlet ของ Master จะตั้งค่าสถานะเมื่อ Master กำลังรับการเชื่อมต่ออยู่ และ Slaves จะสอบถามค่านั้นจาก Master โดยตรง) ขอบคุณสำหรับแนวคิดนี้ - person Liron; 01.10.2013

สำหรับฉัน 1,600 เธรดดูเหมือนมากแต่ไม่ได้มากเกินไปเนื่องจากเป็นการจำลอง หากนี่เป็นแอปพลิเคชันที่ใช้งานจริง ก็อาจจะไม่คุ้มค่ากับการผลิต

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

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

ฉันขอแนะนำให้คุณลองใช้การจำลองใน C หรือ C++ แทน ซึ่งจะสร้างแอปพลิเคชันเนทีฟที่ควรดำเนินการอย่างมีประสิทธิภาพมากขึ้น

person Olof Forshell    schedule 30.09.2013
comment
C# ก็คุ้มค่าที่จะดูเช่นกัน มันทำเธรดได้อย่างถูกต้อง (ต่างจาก Python) และสร้างความตกใจให้กับเธรดที่ใช้เพื่อความสะดวกของ Python น้อยกว่า C/C++ อาจพิสูจน์ได้ว่าเรียบง่ายเกินไปเพื่อความสะดวก - person bazza; 30.09.2013

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

หากคุณต้องการใช้การประมวลผลแบบขนานจริงๆ และเขียนโหนดของคุณราวกับว่าโหนดเหล่านั้นถูกแยกออกจากกันจริงๆ และแลกเปลี่ยนโดยใช้ข้อความเท่านั้น คุณสามารถใช้ Erlang (http://www.erlang.org/) มันเป็นภาษาที่ใช้งานได้ซึ่งเหมาะอย่างยิ่งสำหรับการดำเนินการกระบวนการคู่ขนานและแลกเปลี่ยนข้อความ กระบวนการ Erlang ไม่ได้แมปกับเธรด OS และคุณสามารถสร้างเธรดได้นับพันรายการ อย่างไรก็ตาม Erlang เป็นภาษาที่ใช้งานได้จริงและอาจดูแปลกมากหากคุณไม่เคยใช้ภาษาดังกล่าว และมันก็ไม่ได้เร็วมากเช่นกัน ดังนั้น เช่นเดียวกับ Python ไม่น่าจะรองรับ 1,600 การกระทำทุกๆ 5 มิลลิวินาที เว้นแต่ว่าการกระทำจะค่อนข้างง่าย

สุดท้าย หากคุณไม่ได้รับประสิทธิภาพที่ต้องการโดยใช้ Python หรือ Erlang คุณสามารถย้ายไปที่ C หรือ C++ ได้ อย่างไรก็ตาม อย่าใช้ 1600 เธรด ในความเป็นจริง การใช้เธรดเพื่อให้ได้ประสิทธิภาพนั้นสมเหตุสมผลก็ต่อเมื่อจำนวนเธรดไม่เกินจำนวนเคอร์เนลของ CPU อย่างมาก รูปแบบเครื่องปฏิกรณ์ (ที่มีเกลียวเครื่องปฏิกรณ์หลายเส้น) คือสิ่งที่คุณต้องการในกรณีนี้ (http://en.wikipedia.org/wiki/Reactor_pattern) มีการนำรูปแบบเครื่องปฏิกรณ์ไปใช้อย่างดีเยี่ยมในไลบรารี boost.asio มีการอธิบายไว้ที่นี่: http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio/

person Ellioh    schedule 30.09.2013
comment
เป้าหมายของฉันที่นี่ไม่ใช่การเพิ่มปริมาณงานด้วยหลายเธรด แต่เป็นการจำลองการสื่อสารระหว่างโหนด มีการประมวลผลน้อยมากในแต่ละโหนด ฉันจะดู erlang และดูว่ามันมีลักษณะอย่างไร - person Liron; 30.09.2013

ความคิดสุ่มบางอย่างที่นี่:

ฉันทำได้ค่อนข้างดีกับหลายร้อยเธรดที่ทำงานเช่นนี้ใน Java; สามารถทำได้ด้วยภาษาที่ถูกต้อง (แต่ฉันไม่ได้ลองสิ่งนี้ใน Python)

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

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

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

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

person RalphChapin    schedule 30.09.2013