Coroutine vs Lanjutan vs Generator

147

Apa perbedaan antara coroutine dan lanjutan dan generator?

Mehdi Asgari
sumber
2
Saya bertanya-tanya apakah coroutine dan lanjutan secara efektif setara. Saya tahu adalah mungkin untuk memodelkan coroutine dengan kelanjutan, tetapi apakah mungkin untuk memodelkan kelanjutan dengan coroutine atau tidak karena kelanjutan secara ketat lebih kuat?
nalply

Jawaban:

127

Saya akan mulai dengan generator, karena mereka adalah kasus paling sederhana. Seperti @zvolkov sebutkan, mereka adalah fungsi / objek yang dapat berulang kali dipanggil tanpa kembali, tetapi ketika dipanggil akan mengembalikan (menghasilkan) nilai dan kemudian menunda eksekusi mereka. Ketika mereka dipanggil lagi, mereka akan mulai dari tempat mereka menunda eksekusi dan melakukan hal mereka lagi.

Generator pada dasarnya adalah coroutine yang dipotong (asimetris). Perbedaan antara coroutine dan generator adalah coroutine dapat menerima argumen setelah awalnya disebut, sedangkan generator tidak bisa.

Agak sulit untuk memberikan contoh sepele tentang di mana Anda akan menggunakan coroutine, tetapi inilah upaya terbaik saya. Ambil ini (dibuat) kode Python sebagai contoh.

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

Contoh di mana coroutine digunakan adalah lexers dan parser. Tanpa coroutine dalam bahasa atau ditiru bagaimanapun, kode lexing dan parsing perlu dicampur bersama meskipun mereka benar-benar dua masalah yang terpisah. Tetapi menggunakan coroutine, Anda dapat memisahkan kode lexing dan parsing.

(Saya akan membahas perbedaan antara coroutine simetris dan asimetrik. Cukup dengan mengatakan bahwa mereka setara, Anda dapat mengkonversi dari satu ke yang lain, dan coroutine asimetris - yang merupakan generator yang paling mirip - adalah lebih mudah untuk dipahami. Saya menjelaskan bagaimana seseorang dapat menerapkan coroutine asimetris dengan Python.)

Kelanjutan sebenarnya adalah binatang yang sangat sederhana. Semua itu adalah fungsi yang mewakili titik lain dalam program yang, jika Anda menyebutnya, akan menyebabkan eksekusi secara otomatis beralih ke titik yang diwakili fungsi tersebut. Anda menggunakan versi yang sangat terbatas setiap hari tanpa menyadarinya. Pengecualian, misalnya, dapat dianggap sebagai semacam kelanjutan dari dalam ke luar. Saya akan memberi Anda contoh pseudocode berbasis Python dari kelanjutan.

Katakanlah Python memiliki fungsi yang disebut callcc(), dan fungsi ini mengambil dua argumen, yang pertama adalah fungsi, dan yang kedua adalah daftar argumen untuk memanggilnya. Satu-satunya batasan pada fungsi itu adalah bahwa argumen terakhir yang diambil adalah fungsi (yang akan menjadi kelanjutan kami saat ini).

def foo(x, y, cc):
   cc(max(x, y))

biggest = callcc(foo, [23, 42])
print biggest

Apa yang akan terjadi adalah yang callcc()pada gilirannya akan memanggil foo()dengan kelanjutan saat ini ( cc), yaitu, referensi ke titik dalam program di mana callcc()dipanggil. Ketika foo()memanggil kelanjutan saat ini, itu pada dasarnya sama dengan mengatakan callcc()untuk kembali dengan nilai yang Anda panggil kelanjutan saat ini, dan ketika melakukan itu, itu memutar kembali tumpukan ke tempat kelanjutan saat ini dibuat, yaitu, ketika Anda menelepon callcc().

Hasil dari semua ini adalah bahwa varian Python hipotetis kita akan dicetak '42'.

Saya harap itu membantu, dan saya yakin penjelasan saya dapat ditingkatkan sedikit!

Keith Gaughan
sumber
6
Satu nit: dibatasi lanjutan adalah fungsi, tapi undelimited continuations tidak: okmij.org/ftp/continuations/undelimited.html#delim-vs-undelim
Frank Shearar
2
Itu poin yang bagus. Yang mengatakan, dalam sebagian besar aplikasi praktis, ketika orang mengatakan 'kelanjutan', mereka berbicara tentang kelanjutan sebagian / dibatasi. Membawa berbagai jenis kelanjutan lainnya akan membuat penjelasannya agak membingungkan.
Keith Gaughan
1
Kelanjutan bukan fungsi, meskipun dapat diubah menjadi fungsi. "Itu mengatakan, dalam sebagian besar aplikasi praktis, ketika orang mengatakan 'kelanjutan', mereka berbicara tentang kelanjutan sebagian / dibatasi." Apakah Anda akan menggunakan istilah "kelanjutan" seperti itu? Saya belum pernah bertemu penggunaan seperti itu. Anda juga memberikan contoh untuk kelanjutan yang tidak ditangguhkan, dengan menggunakan panggilan / cc. Operator untuk kelanjutan yang dibatasi biasanya "reset" dan "shift" (mereka mungkin memiliki nama lain).
Ivancho
3
Mari kita mulai dengan fakta bahwa sudah lima tahun sejak saya menulis ini. Anda agak terlambat ke pesta. Kedua, saya tahu bahwa kelanjutan yang tidak didahulukan tidak berfungsi, tetapi Anda tentang Anda mencoba menjelaskan cara kerjanya tanpa merujuknya seperti itu sementara juga menjaga bahasa tetap sederhana. Dari sudut pandang programmer rata-rata, fakta bahwa kelanjutan yang tidak didahulukan tidak kembali hanya menjadikannya fungsi satu-shot, yang tidak benar sesuai definisi fungsi, tetapi setidaknya dapat dimengerti .
Keith Gaughan
2
Saya tidak terlambat untuk pesta karena ini adalah hasil pertama yang saya dapatkan di google ketika saya mencari "coroutine vs generator". Saya berharap dapat menemukan beberapa informasi bagus tentang perbedaan mereka. Lagi pula saya menemukannya di tempat lain. Dan saya bukan orang pertama yang menunjukkan bahwa penjelasan Anda tentang kelanjutan salah. Masalahnya adalah bahwa seseorang akan melakukan kesalahan dan mungkin akan bingung ketika dia bertemu dengan kata yang sama yang digunakan untuk sesuatu yang berbeda.
Ivancho
33

Coroutine adalah salah satu dari beberapa prosedur yang bergantian melakukan pekerjaan mereka dan kemudian berhenti untuk memberikan kontrol kepada coroutine lain dalam kelompok.

Lanjutan adalah "penunjuk ke fungsi" yang Anda lewati untuk beberapa prosedur, yang akan dieksekusi ("dilanjutkan dengan") ketika prosedur itu dilakukan.

Generator (dalam. NET) adalah konstruksi bahasa yang dapat memuntahkan nilai, "menjeda" pelaksanaan metode dan kemudian melanjutkan dari titik yang sama ketika ditanya untuk nilai berikutnya.

zvolkov
sumber
Saya menyadari bahwa jawabannya mungkin tidak akurat tetapi pada tingkat pertanyaan ini saya berusaha menjaganya tetap sederhana. Selain itu, aku tidak benar-benar mengerti semua ini sendiri :)
zvolkov
Generator dalam python mirip dengan versi C #, tetapi diimplementasikan sebagai sintaks khusus untuk membuat turunan objek iterator, yang mengembalikan nilai yang dikembalikan oleh definisi "fungsi" yang Anda berikan.
Benson
2
Koreksi kecil: "... termasuk tumpukan panggilan dan semua variabel TAPI BUKAN NILAI MEREKA" (atau cukup letakkan "semua variabel"). Kelanjutan tidak mempertahankan nilai, mereka hanya berisi tumpukan panggilan.
nalply
Tidak, kelanjutan bukan "penunjuk ke fungsi". Dalam implementasi yang paling naif, itu berisi pointer berfungsi dan lingkungan memegang variabel lokal. Dan itu tidak pernah kembali kecuali jika Anda menggunakan sesuatu seperti panggilan / cc untuk menangkapnya dengan nilai kembali.
NalaGinrut
9

Dalam versi Python yang lebih baru, Anda dapat mengirim nilai ke Generator dengan generator.send(), yang membuat Generator python secara efektif coroutine.

Perbedaan utama antara Generator python, dan generator lainnya, katakanlah greenlet, adalah bahwa dengan python, Anda yield valuehanya dapat kembali ke pemanggil. Sementara di greenlet, target.switch(value)dapat membawa Anda ke target coroutine tertentu dan menghasilkan nilai di mana targetakan terus berjalan.

Yichuan Wang
sumber
3
Tetapi dalam Python, semua yieldpanggilan harus dalam fungsi yang sama, yang disebut "Generator". Anda tidak dapat yielddari sub-fungsi, itulah sebabnya Python disebut semi-coroutine , sedangkan Lua memiliki coroutine asimetris . (Ada proposal untuk memperbanyak hasil panen, tetapi saya pikir itu hanya membuat lumpur air.)
cdunn2001
7
@ cdunn2001: (komentar oleh Winston) Python3.3 memperkenalkan ekspresi "hasil dari" yang memungkinkan Anda menghasilkan dari sub-generator.
Linus Caldwell