ฉันจะตอบคำถามเฉพาะของคุณด้านล่าง แต่คุณน่าจะทำได้ดีเพียงแค่อ่านบทความมากมายของฉันเกี่ยวกับวิธีที่เราออกแบบผลตอบแทนและรอคอย
https://blogs.msdn.microsoft.com/ericlippert/tag/continuation-passing-style/
https://blogs.msdn.microsoft.com/ericlippert/tag/iterators/
https://blogs.msdn.microsoft.com/ericlippert/tag/async/
บทความเหล่านี้บางส่วนล้าสมัยแล้ว รหัสที่สร้างขึ้นมีความแตกต่างกันหลายวิธี แต่สิ่งเหล่านี้จะทำให้คุณมีแนวคิดว่ามันทำงานอย่างไร
นอกจากนี้ถ้าคุณไม่เข้าใจวิธีการ lambdas จะถูกสร้างเป็นชั้นเรียนปิดเข้าใจว่าเป็นครั้งแรก คุณจะไม่สร้างหัวหรือหางของ async ถ้าคุณไม่มี lambdas ลง
เมื่อถึงการรอคอยรันไทม์จะรู้ได้อย่างไรว่าโค้ดส่วนใดควรรันต่อไป
await
ถูกสร้างขึ้นเป็น:
if (the task is not completed)
assign a delegate which executes the remainder of the method as the continuation of the task
return to the caller
else
execute the remainder of the method now
โดยพื้นฐานแล้ว การรอคอยเป็นเพียงการกลับมาที่สวยงาม
มันรู้ได้อย่างไรว่ามันสามารถกลับมาทำงานต่อจากจุดที่ค้างไว้ได้อย่างไรและมันจำได้อย่างไรว่าอยู่ที่ไหน?
คุณจะทำอย่างไรโดยไม่ต้องรอ? เมื่อเมธอด foo เรียกแถบวิธีการเราจำวิธีกลับไปที่จุดกึ่งกลางของ foo โดยที่คนในพื้นที่ทั้งหมดของการเปิดใช้งาน foo ยังคงอยู่ไม่ว่าจะเป็นแถบใดก็ตาม
คุณรู้ว่ามันทำอย่างไรในแอสเซมเบลอร์ บันทึกการเปิดใช้งานสำหรับ foo ถูกผลักลงบนสแต็ก มีคุณค่าของคนในท้องถิ่น เมื่อถึงจุดที่มีการโทรที่อยู่สำหรับส่งคืนใน foo จะถูกผลักเข้าไปในกอง เมื่อแถบเสร็จสิ้นตัวชี้สแต็กและตัวชี้คำสั่งจะถูกรีเซ็ตเป็นตำแหน่งที่ต้องการและ foo จะไปจากจุดที่ค้างไว้
ความต่อเนื่องของรอคอยเป็นสิ่งเดียวกันยกเว้นที่บันทึกจะถูกนำเข้าสู่กองด้วยเหตุผลที่ชัดเจนว่าลำดับของการเปิดใช้งานไม่ได้ในรูปแบบสแต็ค
ผู้รับมอบสิทธิ์ที่รอคอยให้เป็นความต่อเนื่องของงานประกอบด้วย (1) ตัวเลขซึ่งเป็นข้อมูลเข้าในตารางการค้นหาที่ให้ตัวชี้คำสั่งที่คุณต้องดำเนินการต่อไปและ (2) ค่าทั้งหมดของโลคัลและเทมไลบรารี่
มีอุปกรณ์เพิ่มเติมอยู่ที่นั่น ตัวอย่างเช่นใน. NET เป็นสิ่งผิดกฎหมายที่จะแยกไปอยู่ตรงกลางของบล็อกการลองดังนั้นคุณจึงไม่สามารถติดที่อยู่ของรหัสไว้ในบล็อกลองลงในตารางได้ แต่นี่คือรายละเอียดการทำบัญชี ตามแนวคิดแล้วบันทึกการเปิดใช้งานจะถูกย้ายไปยังฮีป
เกิดอะไรขึ้นกับ call stack ปัจจุบันได้รับการบันทึกหรือไม่?
ข้อมูลที่เกี่ยวข้องในบันทึกการเปิดใช้งานปัจจุบันจะไม่ถูกใส่ไว้ในสแต็กตั้งแต่แรก มันถูกจัดสรรออกจากฮีปจาก get-go (พารามิเตอร์ที่เป็นทางการจะถูกส่งไปบนสแต็กหรือในรีจิสเตอร์ตามปกติแล้วคัดลอกไปยังตำแหน่งฮีปเมื่อวิธีการเริ่มต้น)
ไม่มีการจัดเก็บบันทึกการเปิดใช้งานของผู้โทร การรอคอยอาจจะกลับมาหาพวกเขาโปรดจำไว้ดังนั้นพวกเขาจะได้รับการจัดการตามปกติ
โปรดทราบว่านี่เป็นความแตกต่างระหว่างรูปแบบการส่งผ่านความต่อเนื่องที่เรียบง่ายของการรอคอยและโครงสร้างการเรียกที่มีกระแส - ต่อเนื่องที่คุณเห็นในภาษาเช่น Scheme ในภาษาเหล่านั้นต่อเนื่องทั้งหมดรวมทั้งด้านหลังต่อเนื่องเข้าไปในสายที่ถูกจับโดยเรียกร้องซีซี
จะเกิดอะไรขึ้นถ้าวิธีการโทรทำให้เรียกวิธีอื่นก่อนที่มันจะรอทำไมสแต็กไม่ถูกเขียนทับ?
เมธอดเหล่านั้นเรียกกลับดังนั้นเร็กคอร์ดการเปิดใช้งานจึงไม่อยู่ในสแต็กที่จุดรออีกต่อไป
และรันไทม์บนโลกจะทำงานผ่านสิ่งนี้ได้อย่างไรในกรณีที่มีข้อยกเว้นและสแต็กคลายตัว
ในกรณีที่มีข้อยกเว้นที่ไม่ถูกจับข้อยกเว้นจะถูกจับเก็บไว้ในงานและโยนใหม่เมื่อมีการดึงผลลัพธ์ของงาน
จำการทำบัญชีทั้งหมดที่ฉันพูดถึงก่อนหน้านี้ได้ไหม การได้รับความหมายยกเว้นอย่างถูกต้องเป็นความเจ็บปวดอย่างมากขอบอกคุณ
เมื่อถึงผลตอบแทนรันไทม์จะติดตามจุดที่ควรหยิบสิ่งของอย่างไร สถานะตัวทำซ้ำถูกเก็บรักษาไว้อย่างไร
วิธีการเดียวกัน. สถานะของชาวบ้านถูกย้ายไปที่กองและตัวเลขที่แสดงถึงคำสั่งที่MoveNext
ควรกลับมาใช้งานในครั้งต่อไปที่เรียกนั้นจะถูกเก็บไว้พร้อมกับชาวบ้าน
และอีกครั้งมีเฟืองมากมายในบล็อกตัววนซ้ำเพื่อให้แน่ใจว่ามีการจัดการข้อยกเว้นอย่างถูกต้อง