Coroutine ve Devam vs Jeneratör


147

Koroutin ile devam ve üretici arasındaki fark nedir?


2
Coroutines ve devamların etkili bir şekilde eşdeğer olup olmadığını merak ediyorum. Sürekliliklerle birlikte programların modellenmesinin mümkün olduğunu biliyorum, ancak sürekliliklerin kesinlikle daha güçlü olması nedeniyle sürekliliklerin, programlarla birlikte modellenmesi mümkün müdür?
nalply

Yanıtlar:


127

Jeneratörlerle başlayacağım, en basit durum olduklarını görüyorum. @Zvolkov'un belirttiği gibi, bunlar geri dönmeden tekrar tekrar çağrılabilen işlevler / nesnelerdir, ancak çağrıldığında bir değer döndürür (verim) ve ardından yürütmelerini askıya alırlar. Tekrar çağrıldıklarında, yürütmeyi en son askıya aldıkları yerden başlayacaklar ve işlerini tekrar yapacaklardır.

Bir jeneratör aslında bir kısaltılmış (asimetrik) koroutindir. Bir yardımcı program ve üretici arasındaki fark, bir yardımcı programın başlangıçta çağrıldıktan sonra argümanları kabul edebilmesidir, ancak bir üretici bunu yapamaz.

Coroutines'i nerede kullanacağınıza dair önemsiz bir örnek bulmak biraz zor, ama işte en iyi denemem. Bu (yapılmış) Python kodunu örnek olarak alalım.

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

Koroutinlerin kullanıldığı yerlere örnek olarak sözlükler ve ayrıştırıcılar verilebilir. Dilde eşgüdüm olmadan veya bir şekilde taklit edilmeden, kodlama ve ayrıştırma kodu gerçekten iki ayrı endişe olsa da birlikte karıştırılmalıdır. Ancak bir program kullanarak, lexing ve ayrıştırma kodunu ayırabilirsiniz.

(Simetrik ve asimetrik koroutinler arasındaki farkı inceleyeceğim. Eşdeğer olduklarını söylemek için yeterli, birinden diğerine dönüştürebilirsin ve asimetrik koroutinler - en çok benzeyen jeneratörler - Birinin Python'da asimetrik koroutinleri nasıl uygulayabileceğinin altını çiziyordum.)

Devamlar aslında oldukça basit hayvanlardır. Tüm bunlar, programda başka bir noktayı temsil eden işlevlerdir, bu da onu çağırırsanız, yürütmenin otomatik olarak işlevin temsil ettiği noktaya geçmesine neden olur. Farkına bile varmadan her gün çok kısıtlı sürümlerini kullanıyorsunuz. Örneğin istisnalar, bir çeşit içten dışa devam olarak düşünülebilir. Size bir Python tabanlı sahte kod örneği vereceğim.

Diyelim ki Python adlı bir işleve sahipti callcc()ve bu işlev birincisi bir işlev, ikincisi de onu çağırmak için bir argüman listesi olan iki argüman aldı. Bu işlev üzerindeki tek kısıtlama, aldığı son argümanın bir işlev (şu anki devamımız olacak) olacağıdır.

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

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

Ne olur yani callcc()aramayı açacak foo()akım devamında (ile cc) olduğunu, programda noktasında bir başvuru hangi callcc()denirdi. Ne zaman foo()geçerli devamını çağırır, aslında söylemekle aynı olduğunu callcc()size mevcut devamı aradığınız değeri ile dönmek ve bu yapmasından, geçerli devamı oluşturulduğu yerde, yani beni aradığında geri yığını rulolar callcc().

Tüm bunların sonucu, varsayımsal Python varyantımızın basması olacaktır '42'.

Umarım bu yardımcı olur ve açıklamamın biraz geliştirilebileceğinden eminim!


6
Bir nit: sınırlandırılmış süreklilik işlevlerdir, ancak sınırsız süreklilik değildir: okmij.org/ftp/continuations/undelimited.html#delim-vs-undelim
Frank Shearar

2
İyi bir noktaya değindin. Bununla birlikte, çoğu pratik uygulamada, insanlar 'devam' dediğinde, kısmi / sınırlandırılmış devamlardan bahsediyorlar. Diğer çeşitli süreklilikleri getirmek, açıklamayı bir şekilde karıştırırdı.
Keith Gaughan

1
Devamlar işlev değildir, ancak işlevlere dönüştürülebilirler. Diyerek şöyle devam etti: "Çoğu pratik uygulamada, insanlar 'devam' dediğinde, kısmi / sınırlandırılmış devamlardan bahsediyorlar." "Devam" teriminin böyle bir kullanımına işaret eder misiniz? Hiç böyle bir kullanımla karşılaşmadım. Ayrıca call / cc komutunu kullanarak sınırsız bir devam örneği verdiniz. Sınırlı devam eden işleçler genellikle "sıfırla" ve "kaydır" dır (başka adları olabilir).
Ivancho

3
Bunu yazdığımdan beş yıl sonra başlayalım . Partiye biraz geç kaldın. İkincisi, sınırlandırılmamış sürekliliklerin işlev olmadığını biliyorum , ama siz kendiniz dilini açık tutarak aynı zamanda onlardan bahsedmeden nasıl çalıştıklarını açıklamaya çalışıyorsunuz. Ortalama bir programcı açısından bakıldığında, sınırsız bir devam etmenin geri dönmemesi, onu tek seferlik bir fonksiyon haline getirir, bu da bir fonksiyonun tanımına göre doğru değildir , ancak en azından anlaşılabilir .
Keith Gaughan

2
Ben "coroutine vs generator" aradığımda google'da aldığım ilk sonuç olduğu için partiye geç kalmadım. Farklılıkları hakkında iyi bilgiler bulmayı umuyordum. Her neyse, başka bir yerde buldum. Ve devamlarla ilgili açıklamanızın yanlış olduğunu gösteren ilk kişi ben değilim. Sorun şu ki, bir kişi yanlış anlayacak ve muhtemelen daha sonra farklı bir şey için kullanılan aynı kelimeyi karşıladığında karıştırılacaktır.
Ivancho

33

Koroutin, sırayla işlerini yapan ve daha sonra gruptaki diğer koroutinlere kontrol vermek için duraklayan birkaç prosedürden biridir.

Devam, bu prosedür tamamlandığında yürütülecek ("ile devam") bazı prosedürlere ilettiğiniz bir "işleve işaretçi" dir.

Jeneratör (.NET'te), bir değer verebilir, yöntemin yürütülmesini "duraklatabilir" ve bir sonraki değer istendiğinde aynı noktadan devam edebilen bir dil yapısıdır.


Cevabın doğru olmayabileceğinin farkındayım, ancak bu soru seviyesinde basit tutmaya çalıştım. Ayrıca, gerçekten tüm bunları kendim anlamıyorum :)
zvolkov

Python'daki bir jeneratör C # sürümüne benzer, ancak sağladığınız "işlev" tanımı tarafından döndürülen değerleri döndüren bir yineleyici nesnesinin bir örneğini oluşturmak için özel bir sözdizimi olarak uygulanır.
Benson

2
Küçük bir düzeltme: "... çağrı yığını ve tüm değişkenler dahil ANCAK DEĞERLERİ DEĞİL" (veya sadece "tüm değişkenleri" bırakın). Devamlar değerleri korumaz, sadece çağrı yığınını içerir.
nalply

Hayır, devamlar "bir işleve işaretçi" değildir. En saf uygulamada, işlev gösterecek bir işaretçi içerir ve bir ortam yerel değişkenleri tutar. Ve bir return değeri ile yakalamak için call / cc gibi bir şey kullanmadığınız sürece geri dönmez.
NalaGinrut

9

Python'un yeni sürümünde, generator.send()python Generators'ı etkin bir şekilde eşgüdümlü kılan Jeneratörlere değerler gönderebilirsiniz .

Python Jeneratör ve diğer jeneratör, örneğin greenlet arasındaki temel fark, python'da yield valuesadece arayan kişiye geri dönebileceğinizdir. Greenlet'deyken, target.switch(value)sizi belirli bir hedef koroutine götürebilir ve targetçalışmaya devam edeceği bir değer verebilir.


3
Ancak Python'da, tüm yieldçağrılar "Jeneratör" adı verilen aynı fonksiyonda olmalıdır. Yapamazsınız yieldPython en denir nedenle bir alt fonksiyonu, gelen yarı coroutines Lua sahipken, asimetrik coroutines . (Verimleri yaymak için öneriler var, ama bence bu sadece suları çamurlu.)
cdunn2001

7
@ cdunn2001: (Winston tarafından yapılan yorum) Python3.3, alt jeneratörden elde etmenizi sağlayan "verim kaynağı" ifadesini tanıttı.
Linus Caldwell
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.