ความแตกต่างระหว่าง coroutine และความต่อเนื่องและกำเนิดคืออะไร?
ความแตกต่างระหว่าง coroutine และความต่อเนื่องและกำเนิดคืออะไร?
คำตอบ:
ฉันจะเริ่มต้นด้วยเครื่องกำเนิดไฟฟ้าโดยดูว่าเป็นกรณีที่ง่ายที่สุด ดังที่ @ zvolkov กล่าวถึงพวกเขาจะมีฟังก์ชั่น / วัตถุที่สามารถเรียกซ้ำได้โดยไม่ต้องส่งคืน แต่เมื่อถูกเรียกจะส่งคืน (ผลผลิต) ค่าแล้วระงับการทำงานของพวกเขา เมื่อพวกเขาถูกเรียกอีกครั้งพวกเขาจะเริ่มต้นจากที่พวกเขาหยุดการประหารชีวิตครั้งสุดท้ายและทำสิ่งของพวกเขาอีกครั้ง
เครื่องกำเนิดไฟฟ้าเป็นหลัก coroutine ลดลง (ไม่สมมาตร) ความแตกต่างระหว่าง coroutine และตัวกำเนิดคือ coroutine สามารถยอมรับการขัดแย้งหลังจากที่ถูกเรียกในตอนแรกในขณะที่ตัวสร้างไม่สามารถ
มันค่อนข้างยากที่จะเกิดขึ้นกับตัวอย่างเล็ก ๆ น้อย ๆ ที่คุณจะใช้ coroutines แต่นี่คือความพยายามที่ดีที่สุดของฉัน รับรหัส Python นี้ (ทำขึ้น) เป็นตัวอย่าง
def my_coroutine_body(*args):
while True:
# Do some funky stuff
*args = yield value_im_returning
# Do some more funky stuff
my_coro = make_coroutine(my_coroutine_body)
x = 0
while True:
# The coroutine does some funky stuff to x, and returns a new value.
x = my_coro(x)
print x
ตัวอย่างของการใช้ coroutines คือ lexers และ parsers หากไม่มี coroutines ในภาษาหรือเลียนแบบโค้ดเลเยอร์และการแยกวิเคราะห์จะต้องผสมเข้าด้วยกันแม้ว่าจะเป็นข้อกังวลสองประการก็ตาม แต่ใช้ coroutine คุณสามารถแยก lexing และการแยกรหัส
(ฉันจะแปรงมากกว่าความแตกต่างระหว่าง coroutines แบบสมมาตรและแบบอสมมาตรพอเพียงเพื่อบอกว่ามันเท่ากันคุณสามารถแปลงจากแบบหนึ่งไปอีกแบบหนึ่งได้ ง่ายต่อการเข้าใจฉันกำลังสรุปว่าจะใช้ Coroutines แบบอสมมาตรใน Python ได้อย่างไร)
การต่อเนื่องเป็นสัตว์ที่ค่อนข้างง่าย ทั้งหมดที่พวกเขามีคือฟังก์ชั่นที่เป็นตัวแทนของจุดอื่นในโปรแกรมซึ่งถ้าคุณเรียกมันว่าจะทำให้การดำเนินการเพื่อสลับไปยังจุดที่ฟังก์ชั่นโดยอัตโนมัติ คุณใช้เวอร์ชันที่ จำกัด มาก ๆ ทุกวันโดยที่ไม่ทราบเลย ยกตัวอย่างเช่นข้อยกเว้นสามารถถูกมองว่าเป็นความต่อเนื่องภายใน - ออก ฉันจะให้ตัวอย่าง pseudocode ที่ใช้ Python ของคุณสำหรับการต่อเนื่อง
สมมติว่า Python มีฟังก์ชั่นที่เรียกว่าcallcc()
และฟังก์ชั่นนี้ใช้สองอาร์กิวเมนต์แรกคือฟังก์ชันและที่สองเป็นรายการอาร์กิวเมนต์ที่จะเรียกใช้ ข้อ จำกัด เพียงอย่างเดียวในฟังก์ชั่นนั้นก็คือว่าอาร์กิวเมนต์สุดท้ายที่ใช้จะเป็นฟังก์ชัน (ซึ่งจะเป็นความต่อเนื่องในปัจจุบันของเรา)
def foo(x, y, cc):
cc(max(x, y))
biggest = callcc(foo, [23, 42])
print biggest
สิ่งที่จะเกิดขึ้นก็คือcallcc()
จะfoo()
มีการเรียกกลับด้วยความต่อเนื่องในปัจจุบัน ( cc
) นั่นคือการอ้างอิงถึงจุดในโปรแกรมที่callcc()
ถูกเรียก เมื่อfoo()
เรียกความต่อเนื่องในปัจจุบันมันก็เหมือนกับการบอกcallcc()
ให้กลับมาพร้อมกับค่าที่คุณกำลังเรียกความต่อเนื่องในปัจจุบันด้วยและเมื่อมันทำเช่นนั้นมันจะย้อนกลับสแต็กไปยังตำแหน่งที่สร้างความต่อเนื่องในปัจจุบันcallcc()
.
'42'
ผลจากการทั้งหมดนี้จะเป็นไปได้ว่าตัวแปรหลามสมมุติเราจะพิมพ์
ฉันหวังว่าจะช่วยได้และฉันมั่นใจว่าคำอธิบายของฉันสามารถปรับปรุงได้ในไม่ช้า!
Coroutine เป็นหนึ่งในหลาย ๆ โพรซีเดอร์ที่ผลัดกันทำงานแล้วหยุดเพื่อควบคุม Coroutines อื่น ๆ ในกลุ่ม
ความต่อเนื่องเป็น "ตัวชี้ไปยังฟังก์ชั่น" ที่คุณส่งไปยังบางโพรซีเดอร์ที่จะดำเนินการ ("ดำเนินการต่อด้วย") เมื่อทำโพรซีเดอร์นั้น
ตัวสร้าง (ใน. NET) เป็นโครงสร้างภาษาที่สามารถคายออกค่า "หยุด" การดำเนินการของวิธีการแล้วดำเนินการต่อจากจุดเดียวกันเมื่อถูกถามถึงค่าถัดไป
ในเวอร์ชันที่ใหม่กว่าของ Python คุณสามารถส่งค่าไปยังเครื่องกำเนิดไฟฟ้าด้วยgenerator.send()
ซึ่งทำให้เครื่องกำเนิดงูหลามมีประสิทธิภาพ
ความแตกต่างที่สำคัญระหว่าง python Generator และตัวสร้างอื่น ๆ คือ greenlet นั่นคือใน python คุณyield value
สามารถกลับไปที่ caller ได้เท่านั้น ในขณะที่อยู่ในกรีนเล็ตtarget.switch(value)
คุณสามารถพาคุณไปยังCoroutine เป้าหมายที่เฉพาะเจาะจงและให้ค่าที่target
ต้องการให้ทำงานต่อไป
yield
โทรทั้งหมดจะต้องอยู่ในฟังก์ชันเดียวกันซึ่งเรียกว่า "เครื่องกำเนิด" คุณไม่สามารถyield
จากย่อยฟังก์ชั่นซึ่งเป็นสาเหตุของงูหลามจะเรียกว่ากึ่ง coroutines-ขณะ Lua มีcoroutines ไม่สมมาตร (มีข้อเสนอที่จะเผยแพร่ผลผลิต แต่ฉันคิดว่าคนเหล่านั้นเพียงโคลน)