Co to jest coroutine?

204

Co to jest coroutine? Jak są one powiązane z współbieżnością?

tak
źródło
2
Kod współbieżny niekoniecznie musi działać równolegle (nie wprowadzajmy nowych terminów).
lucid_dreamer
2
Napisałem jedną bibliotekę coroutine ze standardowym C, obsługującą komunikaty GUI select / poll / eplll / kqueue / iocp / Win dla Linux, BSD i Windows. To projekt typu open source na github.com/acl-dev/libfiber . Porady będą mile widziane.
ShuXin Zheng
Więcej interesujących informacji tutaj: stackoverflow.com/q/16951904/14357
spędzić
Mogę sobie wyobrazić, że to pytanie zostanie odrzucone, jeśli zostanie zadane w obecnej epoce. Nie jesteś pewien, dlaczego istnieje tak ogromna różnica w postrzeganiu społeczności w porównaniu z poprzednimi?
tnkh
współprogram jest funkcją, która może wstrzymać jej wykonanie przed osiągnięciem zwrotu, a to może pośrednio przekazać kontrolę do innego współprogram przez jakiś czas.
hassanzadeh.sd

Odpowiedzi:

138

Korpusy i współbieżność są w dużej mierze ortogonalne. Korpusy są ogólną strukturą kontrolną, w której kontrola przepływu jest wspólnie przekazywana między dwiema różnymi procedurami bez powrotu.

Polecenie „fed” w Pythonie jest dobrym przykładem. Tworzy kortynę. Po napotkaniu „wydajności” zapisywany jest bieżący stan funkcji, a kontrola powraca do funkcji wywołującej. Funkcja wywołująca może następnie przenieść wykonanie z powrotem do funkcji ustępującej, a jej stan zostanie przywrócony do punktu, w którym napotkano „wydajność” i wykonywanie będzie kontynuowane.

użytkownik21714
źródło
19
Jaka jest różnica między bezpośrednim wywoływaniem funkcji a uzyskiwaniem z coroutine z zawijaniem tej funkcji do tego coroutine?
Ming Li
3
Lepiej byłoby wyjaśnić, że te dwa pojęcia nie są tak naprawdę „ortogonalne” w tym kontekście. Na pewno możesz narysować, jak te dwie koncepcje są do siebie podobne. Pomysł przekazania kontroli między dwiema lub więcej rzeczami jest bardzo podobny.
steviejay,
8
Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning.<- To jest współbieżność. Słowo, którego szukasz, to równoległość.
Adam Arold,
@steviejay orthogonal = Not similar to each other?
tonix
1
@tonix Powiedziano mi, że orthogonaloznacza to „niezależne od siebie”.
Rick
77

Z programowania w Lua , Coroutinessekcja „ ”:

Korpus jest podobny do wątku (w sensie wielowątkowości): jest to linia wykonania, z własnym stosem, własnymi zmiennymi lokalnymi i własnym wskaźnikiem instrukcji; ale ma wspólne zmienne globalne i głównie wszystko inne z innymi firmami. Główna różnica między wątkami a coroutines polega na tym, że koncepcyjnie (lub dosłownie w maszynie wieloprocesorowej) program z wątkami uruchamia kilka wątków równolegle. Z drugiej strony, coroutines współpracują ze sobą: w dowolnym momencie program z coroutines uruchamia tylko jedną ze swoich coroutines, a ta uruchomiona coroutine zawiesza wykonywanie tylko wtedy, gdy wyraźnie żąda zawieszenia.

Chodzi o to, że coroutine są „współpracujące”. Nawet w systemie wielordzeniowym w danym momencie działa tylko jedna koruta (ale wiele wątków może działać równolegle). Między korporacjami nie ma prawa zapobiegawczego, działająca coroutine musi jawnie zrezygnować z wykonania.

Aby zobaczyć „ concurrency”, możesz odnieść slajd Roba Pike'a :

Współbieżność to kompozycja niezależnie wykonujących obliczeń.

Tak więc podczas wykonywania coroutine A przekazuje kontrolę do coroutine B. Następnie po pewnym czasie coroutine B przekazuje kontrolę z powrotem do coroutine A. Ponieważ istnieje zależność między coroutine i muszą one działać w tandemie, więc dwie coroutine niewspółbieżne .

Nan Xiao
źródło
6
Korpusy nie działają niezależnie. Zmieniają się, czekając, aż druga wykona część pracy. Aktywnie koordynują się ze sobą. To jest przeciwieństwo definicji współbieżności Roba Pikesa.
Erick G. Hagstrom
2
@ ErickG.Hagstrom: Chociaż nie wykonują się one niezależnie, logika każdej coroutine może być niezależna, prawda? Jeśli ma rację, to jest tak, jakby nie działał zapobiegawczo system operacyjny działający na jednordzeniowym procesorze, jeden proces musi zrezygnować z procesora, aby umożliwić uruchomienie innych zadań.
Nan Xiao
6
Istnieje różnica między rezygnacją z procesora, aby umożliwić uruchomienie innego zadania , a powiadomieniem jakiegoś konkretnego procesu, że czas wykonać. Korpusy robią to drugie. To w żadnym sensie nie jest niezależne.
Erick G. Hagstrom
7
@ChrisClark Zgadzam się z tobą. Korpusy są współbieżne. Oto cytat z wikipedii: Coroutines są bardzo podobne do wątków. Jednak coroutines są wielozadaniowe, podczas gdy wątki są zwykle zapobiegawczo wielozadaniowe. Oznacza to, że zapewniają współbieżność, ale nie równoległość .
smwikipedia,
3
I: Wielozadaniowość kooperacyjna, znana również jako nieprzekazywająca wielozadaniowość, to styl wielozadaniowości komputera, w którym system operacyjny nigdy nie inicjuje zmiany kontekstu z uruchomionego procesu na inny proces. Zamiast tego procesy dobrowolnie dają kontrolę okresowo lub gdy są bezczynne lub logicznie blokowane, aby umożliwić jednoczesne uruchamianie wielu aplikacji.
smwikipedia,
47

Uważam, że większość odpowiedzi jest zbyt techniczna, mimo że jest to pytanie techniczne. Trudno mi było zrozumieć proces korupcji. W pewnym sensie to rozumiem, ale potem nie rozumiem tego w tym samym czasie.

Uważam, że ta odpowiedź tutaj jest bardzo pomocna:

https://dev.to/thibmaek/explain-coroutines-like-im-five-2d9

Cytat z Idan Arye:

Aby rozwinąć twoją historię, chciałbym napisać coś takiego:

Zaczynasz oglądać kreskówkę, ale to jest wprowadzenie. Zamiast oglądać wstęp, przełączasz się do gry i wchodzisz do lobby online - ale potrzebuje 3 graczy i tylko ty i twoja siostra są w nim. Zamiast czekać na dołączenie innego gracza, przełącz się na pracę domową i odpowiedz na pierwsze pytanie. Drugie pytanie zawiera link do filmu na YouTube, który musisz obejrzeć. Otwierasz go - i zaczyna się ładować. Zamiast czekać na załadowanie, przełączasz się z powrotem na kreskówkę. Wstęp jest zakończony, więc możesz oglądać. Teraz są reklamy - ale tymczasem dołączył trzeci gracz, więc przełączasz się na grę I tak dalej ...

Chodzi o to, że nie tylko przełączasz zadania naprawdę szybko, aby wyglądało to tak, jakbyś robił wszystko od razu. Wykorzystujesz czas, który czekasz, aż coś się wydarzy (IO), aby wykonać inne czynności wymagające Twojej bezpośredniej uwagi.

Zdecydowanie sprawdź link, nie mogę wszystkiego zacytować.

mr1031011
źródło
6
Bardzo prosta i bezpośrednia ilustracja. +1 za to.
Taslim Oseni
świetna ilustracja. Zbudowałem podobną historię - stojąc w kolejce, aby odebrać paczkę. ale na dzień dzisiejszy twój jest znacznie bardziej realistyczny, kto stoi w kolejce, gdy są dostawy door2door? Lol
apolak
1
To niesamowite wytłumaczenie. Z samego cytatu jest bardzo jasne.
Farruh Habibullaev
15

Coroutine jest podobny do podprogramu / wątków. Różnica polega na tym, że gdy wywołujący wywoła podprogram / wątki, nigdy nie powróci do funkcji wywołującej. Ale coroutine może powrócić do programu wywołującego po wykonaniu kilku fragmentów kodu, umożliwiając programowi wywołującemu wykonanie własnego kodu i powrót do punktu coroutine, w którym przerwał wykonywanie i kontynuował stamtąd. to znaczy. Korpus ma więcej niż jeden punkt wejścia i wyjścia

Migotanie
źródło
Nie jest tak podobny do wątków - które działają niezależnie i jednocześnie (oddzielne rdzenie równolegle). Ponadto porównanie podprogramów kończy się niepowodzeniem w tym sensie, że istnieje wiele niezależnych ścieżek wykonania i nie zwracają sobie wyników.
javadba
11
  • Coroutines to świetne funkcje dostępne w języku Kotlin
  • Coroutines to nowy sposób pisania kodu asynchronicznego, nieblokującego (i wiele więcej)
  • Coroutine to lekkie nici. Lekki wątek oznacza, że ​​nie jest mapowany na wątek macierzysty, więc nie wymaga przełączania kontekstu na procesorze, więc są szybsze.
  • nie jest mapowany na wątek macierzysty
  • Zarówno coroutines, jak i wątki są wielozadaniowe. Różnica polega jednak na tym, że wątkami zarządza system operacyjny, a użytkownicy - użytkownikami.

Zasadniczo istnieją dwa rodzaje Coroutines:

  1. Bez stosów
  2. Stackful

Kotlin implementuje coroutines bez stosu - oznacza to, że coroutines nie mają własnego stosu, więc nie mapują się na natywny wątek.

Oto funkcje uruchamiania coroutine:

launch{}

async{}

Możesz dowiedzieć się więcej tutaj:

https://www.kotlindevelopment.com/deep-dive-coroutines/

https://blog.mindorks.com/what-are-coroutines-in-kotlin-bf4fecd476e9

Dhaval Jivani
źródło
1
Dobra odpowiedź! Przydatne dla programistów Kotlin i Android.
Malwinder Singh
5

Z drugiej strony, w geventbibliotece Pythona jest coroutineoparta na bibliotece biblioteka sieciowa, która zapewnia funkcje podobne do wątków, takie jak asynchroniczne żądania sieciowe, bez konieczności tworzenia i niszczenia wątków. coroutineBiblioteka jest używana greenlet.

Joseph
źródło
2

Z Python Coroutine :

Wykonywanie coroutines w Pythonie można zawiesić i wznowić w wielu punktach (patrz coroutine). Wewnątrz funkcji coroutine czekają, a identyfikatory asynchroniczne stają się zastrzeżonymi słowami kluczowymi; czekaj na wyrażenia, asynchroniczne i asynchroniczne z mogą być używane tylko w obiektach funkcji coroutine.

Z Coroutines (C ++ 20)

Koruta jest funkcją, która może zawiesić wykonanie, aby zostać wznowiona później . Korpusy są bezładne: zawieszają wykonywanie, wracając do programu wywołującego. Pozwala to na sekwencyjny kod, który wykonuje się asynchronicznie (np. Do obsługi nieblokujących We / Wy bez wyraźnych wywołań zwrotnych), a także obsługuje algorytmy na leniwie obliczonych nieskończonych sekwencjach i innych zastosowaniach.

Porównaj z odpowiedzią innych:

Moim zdaniem wznowiona później część jest zasadniczą różnicą, podobnie jak @ Twinkle's.
Chociaż wiele pól dokumentu jest wciąż w toku, ta część jest podobna do większości odpowiedzi, z wyjątkiem @Nan Xiao

Z drugiej strony, coroutines współpracują ze sobą: w dowolnym momencie program z coroutines uruchamia tylko jedną ze swoich coroutines, a ta uruchomiona coroutine zawiesza wykonywanie tylko wtedy, gdy wyraźnie żąda zawieszenia.

Ponieważ cytat pochodzi z Programu w Lua, być może jest on związany z językiem (obecnie nie zna Lua), nie wszystkie dokumenty wspominają tylko o jednej części.

Relacja z równoczesnym:
w Coroutines znajduje się część „ Egzekucyjna” (C ++ 20) .
Oprócz szczegółów istnieje kilka stanów.

When a coroutine begins execution  
When a coroutine reaches a suspension point  
When a coroutine reaches the co_return statement  
If the coroutine ends with an uncaught exception  
When the coroutine state is destroyed either because it terminated via co_return or uncaught exception, or because it was destroyed via its handle 

jako komentarz od @Adam Arold pod odpowiedzią @ user217714. To współbieżność.
Ale różni się od wielowątkowości. z std :: thread

Wątki umożliwiają jednoczesne wykonywanie wielu funkcji. Wątki rozpoczynają wykonywanie natychmiast po zbudowaniu powiązanego obiektu wątku (w oczekiwaniu na opóźnienia w planowaniu systemu operacyjnego), zaczynając od funkcji najwyższego poziomu podanej jako argument konstruktora. Zwracana wartość funkcji najwyższego poziomu jest ignorowana, a jeśli zakończy się przez zgłoszenie wyjątku, wywoływane jest std :: terminate. Funkcja najwyższego poziomu może przekazać swoją wartość zwracaną lub wyjątek dzwoniącemu przez std :: promise lub przez modyfikację zmiennych wspólnych (które mogą wymagać synchronizacji, patrz std :: mutex i std :: atomic)

Ponieważ jest to współbieżność, działa jak wielowątkowość, zwłaszcza gdy nie da się uniknąć oczekiwania (z perspektywy systemu operacyjnego), dlatego też jest myląca.

Shihe Zhang
źródło
1

Korpus jest szczególnym rodzajem podprogramu. Zamiast relacji master-slave między dzwoniącym a wywoływanym podprogramem, który istnieje w przypadku konwencjonalnych podprogramów, dzwoniący i nazywane coroutines są bardziej sprawiedliwi.

  • Korpus jest podprogramem, który ma wiele pozycji i sam je kontroluje - obsługiwany bezpośrednio w Lua

  • Nazywany również kontrolą symetryczną: osoba wywołująca i nazywane coroutines są na równych zasadach

  • Wezwanie coroutine nosi nazwę CV

  • Pierwsze wznowienie coroutine jest na początku, ale kolejne wywołania pojawiają się w punkcie tuż po ostatniej wykonanej instrukcji w coroutine

  • Korpusy wielokrotnie się wznawiają, być może na zawsze

  • Korpusy zapewniają quasi-równoczesne wykonywanie jednostek programu (coroutines); ich wykonanie jest przeplatane, ale nie nakłada się

Przykład 1 Przykład 2

BoraKurucu
źródło
1

Wyjaśnienie tego linku jest dość proste. Żadna z tych odpowiedzi nie próbuje wyjaśnić zbieżności z równoległością, z wyjątkiem ostatniego punktu w tej odpowiedzi .

  1. co to jest współbieżne (program)?

cytowany z „programowania Erlanga” autorstwa legendarnego Joe Armstronga:

współbieżny program może działać potencjalnie szybciej na komputerze równoległym.

  • program współbieżny to program napisany w równoległym języku programowania. Piszemy programy współbieżne ze względu na wydajność, skalowalność lub odporność na awarie.

  • współbieżny język programowania to język, który ma wyraźne konstrukcje językowe do pisania współbieżnych programów. Te konstrukcje są integralną częścią języka programowania i zachowują się w ten sam sposób we wszystkich systemach operacyjnych.

  • komputer równoległy to komputer, który ma kilka jednostek przetwarzających (procesorów lub rdzeni), które mogą działać w tym samym czasie.

Zatem współbieżność to nie to samo co równoległość. Nadal możesz pisać współbieżne programy na komputerze z jednym rdzeniem. Harmonogram podziału czasu sprawi, że poczujesz, że twój program działa jednocześnie.

Współbieżny program może działać równolegle na komputerze równoległym, ale nie jest to gwarantowane . System operacyjny może dać ci tylko jeden rdzeń do uruchomienia twojego programu.

Dlatego współbieżność to model oprogramowania współbieżnego programu, który nie oznacza, że ​​Twój program może działać równolegle fizycznie.

  1. koruta i współbieżność

Słowo „coroutine” składa się z dwóch słów: „co” (spółdzielnia) i „procedury” (funkcje).

za. czy osiąga współbieżność lub równoległość?

Mówiąc prościej, omówmy to na jednym rdzeniu .

Współbieżność osiągana jest dzięki udziałom czasowym z systemu operacyjnego. Wątek wykonuje swój kod w przypisanych ramach czasowych na rdzeniu procesora. Może być przejęty przez system operacyjny. Może także sprawować kontrolę nad systemem operacyjnym.

Z drugiej strony, coroutine daje kontrolę nad inną coroutine w wątku, a nie OS. Tak więc wszystkie coroutines w wątku nadal wykorzystują ramy czasowe tego wątku bez poddawania rdzenia procesora innym wątkom zarządzanym przez system operacyjny.

Dlatego możesz pomyśleć, że coroutine osiąga udziały czasu przez użytkownika, a nie przez system operacyjny (lub quasi-równoległość). Coroutines działają na tym samym rdzeniu, który jest przypisany do wątku, który uruchamia te coroutines.

Czy Coroutine osiąga równoległość? Jeśli jest to kod związany z procesorem, nie. Podobnie jak udziały czasu, sprawia, że ​​czujesz, że działają równolegle, ale ich egzekucje są przeplatane, a nie nakładające się. Jeśli jest związany z IO, tak, osiąga równoległy sprzęt (urządzenia IO), a nie kod.

b. różnica z wywołaniem funkcji?

wprowadź opis zdjęcia tutaj

Jak pokazuje zdjęcie, nie trzeba dzwonić, returnaby przełączyć kontrolę. Może ulec bez return. Korpus zapisuje i współdzieli stan w bieżącej ramce funkcji (stosie). Jest więc znacznie lżejszy niż funkcja, ponieważ nie trzeba zapisywać rejestrów i zmiennych lokalnych, aby układać stosy i przewijać stos wywołań call ret.

Izana
źródło
0

Rozwinę odpowiedź @ @ user21714. Korpusy są niezależnymi ścieżkami wykonania, które nie mogą działać jednocześnie. Zależą od kontrolera - na przykład pythonbiblioteki kontrolera - do obsługi przełączania między tymi ścieżkami. Ale żeby to zadziałało, same korporacje muszą się przywołaćyield lub podobne struktury, które pozwalają na wstrzymanie ich wykonywania.

Wątki zamiast tego działają na niezależnych zasobach obliczeniowych i równolegle ze sobą. Ponieważ znajdują się na różnych zasobach, nie ma potrzeby wywoływania dochodu, aby umożliwić kontynuowanie innych ścieżek wykonania.

Możesz zobaczyć ten efekt, uruchamiając program wielowątkowy - np. jvmAplikację - w której wykorzystuje się wszystkie osiem core i7rdzeni hiperwątkowych: możesz zobaczyć 797% wykorzystania w Activity Monitorlub Top. Zamiast tego podczas uruchamiania typowego pythonprogramu - nawet takiego z coroutineslub python threading- wykorzystanie będzie maksymalne na 100%. Tj. Jeden wątek maszyny.

javadba
źródło