Unity coroutine กับเธรด


13

ความแตกต่างระหว่าง coroutine และเธรดคืออะไร? มีข้อดีของการใช้อย่างใดอย่างหนึ่งมากกว่าอื่น ๆ ?


3
Coroutines ทำงานบนเธรดหลัก
Woltus


2
คุณไม่สามารถใช้ฟังก์ชัน Unity ใน Thread ได้ Coroutines สามารถ
Hellium


1
@Hellium Correction คุณไม่สามารถใช้ฟังก์ชัน Unity ใด ๆ ในเธรดอื่นเช่นฟังก์ชัน Unity สามารถใช้ในเธรดหลักได้
Pharap

คำตอบ:


24

ในขณะที่ Coroutines ดูเหมือนจะทำงานเหมือนกับเธรดในตอนแรกพวกเขาไม่ได้ใช้มัลติเธรดใด ๆ yieldพวกเขาจะดำเนินการตามลำดับจนกว่าพวกเขาจะ เครื่องยนต์จะตรวจสอบ coroutines ผลทั้งหมดเป็นส่วนหนึ่งของวงหลักของตัวเอง (ในสิ่งที่ชี้ว่าขึ้นอยู่กับชนิดของyield, ตรวจสอบแผนภาพนี้สำหรับข้อมูลเพิ่มเติม ) ต่อพวกเขาหนึ่งหลังจากที่อื่นจนกว่าพวกเขาต่อไปyieldและจากนั้นดำเนินการกับวงหลัก

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

ในทางกลับกันคุณไม่มีความรู้อย่างแน่นอนเกี่ยวกับสถานะของลูปหลักของ Unity ในขณะนี้ (อันที่จริงแล้วอาจไม่ได้ทำงานเลย) ดังนั้นเธรดของคุณอาจทำให้เกิดความเสียหายค่อนข้างมากด้วยการทำบางอย่างในเวลาที่ไม่ควรทำสิ่งนั้น อย่าสัมผัสการทำงานใด ๆ สามัคคีพื้นเมืองจากย่อยหัวข้อ หากคุณต้องการสื่อสารระหว่าง sub-thread และ thread หลักของคุณให้ thread เขียนไปยัง container-object (!) thread-safe (!) และให้ MonoBehaviour อ่านข้อมูลนั้นในระหว่างฟังก์ชั่น Unity ปกติ

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

สรุป:

  • หากคุณต้องการใช้การประมวลผลแบบอะซิงโครนัสเพื่อแสดงตรรกะของเกมให้ใช้ coroutines
  • หากคุณต้องการใช้การดำเนินการแบบอะซิงโครนัสเพื่อใช้ประโยชน์หลายคอร์ของ CPU ให้ใช้เธรด

ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
MichaelHouse

10

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

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

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

ข้อดีของ coroutines คือพวกเขาเข้าใจง่าย ข้อผิดพลาดที่คุณคาดเดาได้นั้นมีมากกว่า โดยทั่วไปแล้วพวกเขายังเรียกร้องให้มีทรัพยากรน้อยลงซึ่งจะมีประโยชน์เมื่อคุณปีนขึ้นไปสู่ ​​10 coronines หรือเธรดจำนวนมาก Candid Moon พูดถึงในความคิดเห็นที่ว่าถ้าคุณยังไม่ได้ศึกษาหัวข้ออย่างถูกต้องเพียงติดกับ coroutines และพวกเขาถูกต้อง Coroutines นั้นใช้งานง่ายกว่ามาก

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

เหตุผลสำหรับความซับซ้อนพิเศษนี้จริง ๆ แล้วง่ายมาก แบบจำลองมัลติทาสกิ้งแบบ preemptive นั้นคล้ายกับแบบจำลองแบบมัลติเธรดซึ่งอนุญาตให้คุณไม่เพียง แต่ขัดจังหวะเธรดอื่น ๆ แต่เพื่อรันเธรดแบบเคียงข้างกันบนแกนที่ต่างกัน นี่เป็นวิธีที่มีประสิทธิภาพอย่างไม่น่าเชื่อเป็นวิธีเดียวที่จะใช้ประโยชน์จากซีพียู quad core และ hex code ใหม่ที่กำลังจะออกมา แต่จะเปิดกล่อง pandoras ขึ้นมา กฎการซิงโครไนซ์สำหรับวิธีการจัดการข้อมูลนี้ในโลกแบบมัลติเธรดนั้นโหดร้ายทางบวก ในโลก C ++ มีบทความทั้งหมดที่อุทิศให้MEMORY_ORDER_CONSUMEซึ่งเป็นมุมหนึ่ง itty-bitty-teeny-weenie ของการซิงโครไนซ์แบบมัลติเธรด

ข้อเสียของการทำเกลียว? ง่าย: มันยาก คุณสามารถเจอบั๊กทั้งหมดที่คุณไม่เคยเห็นมาก่อน หลายคนเรียกว่า "heisenbugs" ซึ่งบางครั้งจะปรากฏขึ้นและหายไปเมื่อคุณทำการดีบั๊ก เครื่องมือที่คุณได้รับเพื่อจัดการกับสิ่งเหล่านี้มีประสิทธิภาพมาก แต่ก็ยังอยู่ในระดับที่ต่ำมาก พวกเขาได้รับการออกแบบให้มีประสิทธิภาพในสถาปัตยกรรมของชิปที่ทันสมัยมากกว่าการออกแบบให้ใช้งานง่าย

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

ความคิดเห็นของ Candid Moon ที่ติดกับ coroutines เป็นคำแนะนำของฉันเช่นกัน หากคุณต้องการพลังของเธรดให้คอมมิต ออกไปและเรียนรู้หัวข้อจริงๆอย่างเป็นทางการ เรามีเวลาหลายสิบปีในการหาวิธีจัดระเบียบวิธีที่ดีที่สุดในการคิดเกี่ยวกับเธรดเพื่อให้คุณได้รับผลลัพธ์ที่น่าเชื่อถือได้อย่างปลอดภัยก่อนกำหนดและเพิ่มประสิทธิภาพตามที่คุณไป ตัวอย่างเช่นหลักสูตรที่มีสติทั้งหมดจะสอน mutexes ก่อนการสอนตัวแปรเงื่อนไข หลักสูตรมีเหตุผลทั้งหมดที่ครอบคลุม atomics จะสอน mutexes และตัวแปรเงื่อนไขอย่างสมบูรณ์ก่อนที่จะพูดถึงว่าอะตอมมีอยู่จริง (หมายเหตุ: ไม่มีสิ่งใดที่เป็นแบบฝึกหัดที่มีเหตุผลเกี่ยวกับอะตอมมิกส์) ลองเรียนรู้การทำเกลียวทีละน้อยและคุณขอร้องให้เป็นไมเกรน


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

... แต่เป็นวิธีสำหรับเธรดที่จัดการ y () และ z () เพื่อรอจนกว่าจะถูกทริกเกอร์และจากนั้นวิธีที่เธรดหลักจะรอหลังจากรัน x () จนกระทั่ง y () และ z () เสร็จสิ้นแล้ว
supercat

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

แน่นอนจะต้องมีบางส่วนjoinประสานและบรรลุประสิทธิภาพด้านบนโดยทั่วไปจะต้องมีอะไรที่ดีกว่า ประเด็นของฉันคือการใฝ่หาเศษเสี้ยวของผลประโยชน์ด้านประสิทธิภาพที่เป็นไปได้ของการทำเกลียวได้อย่างง่ายดายบางครั้งอาจดีกว่าการใช้วิธีการทำเกลียวที่ซับซ้อนกว่าเพื่อเก็บเกี่ยวเศษส่วนที่ใหญ่กว่า
supercat

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

2

ในเงื่อนไขที่ง่ายที่สุดที่เป็นไปได้ ...


หัวข้อ

เธรดไม่ได้ตัดสินใจว่าจะให้ผลผลิตเมื่อใดระบบปฏิบัติการ ('OS' เช่น Windows) จะตัดสินใจเมื่อมีการให้บริการชุดข้อความ ระบบปฏิบัติการเกือบทั้งหมดมีความรับผิดชอบสำหรับการจัดตารางเวลาเธรดมันตัดสินใจว่าเธรดที่จะเรียกใช้เมื่อใดที่จะเรียกใช้เธรดเหล่านี้และนานเท่าใด

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

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

หัวข้อนั้นยังถือว่าเป็น 'หนัก' เนื่องจากมีค่าใช้จ่ายจำนวนมากซึ่งหมายความว่ามีการปรับเวลาเป็นจำนวนมากเมื่อสลับเธรด


coroutines

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

อย่างไรก็ตามนี่เป็นความรับผิดชอบที่สำคัญเช่นกันหาก coroutine ไม่สามารถให้ผลได้อย่างถูกต้องมันอาจใช้เวลาประมวลผลนานมาก

Coroutines โดยทั่วไปไม่จำเป็นต้องสลับบริบทและทำให้สลับเข้าและออกได้อย่างรวดเร็วและค่อนข้างเบา


สรุป:

เกลียว:

  • ซิงโครนัสหรืออะซิงโครนัส
  • ให้ผลผลิตโดยระบบปฏิบัติการ
  • ให้ผลแบบสุ่ม
  • หนัก

coroutine:

  • พร้อมกัน
  • ให้ผลตอบแทนตนเอง
  • ให้ผลตอบแทนตามตัวเลือก
  • มีน้ำหนักเบา

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

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