Cos'è una coroutine?


204

Cos'è una coroutine? In che modo sono collegati alla concorrenza?


2
Il codice simultaneo non deve necessariamente essere eseguito in "parallelo" (non introduciamo nuovi termini).
lucid_dreamer,

2
Ho scritto una libreria coroutine con C standard, supportando i messaggi select / poll / eplll / kqueue / iocp / Win GUI per Linux, BSD e Windows. È un progetto open source in github.com/acl-dev/libfiber . Il consiglio sarà benvenuto.
ShuXin Zheng,

Altre informazioni interessanti qui: stackoverflow.com/q/16951904/14357
spender

Immagino che questa domanda verrà annullata se verrà posta in questa era attuale. Non sei sicuro del perché ci sia una così grande differenza nella percezione della comunità rispetto a prima?
tnkh,

una coroutine è una funzione che può sospenderne l'esecuzione prima di raggiungere il ritorno, e può passare indirettamente il controllo a un'altra coroutine per qualche tempo.
hassanzadeh.sd,

Risposte:


138

Le coroutine e la concorrenza sono in gran parte ortogonali. Le coroutine sono una struttura di controllo generale in base alla quale il controllo del flusso viene passato in modo cooperativo tra due diverse routine senza tornare.

L'istruzione 'yield' in Python è un buon esempio. Crea un coroutine. Quando viene rilevato il "rendimento", lo stato corrente della funzione viene salvato e il controllo viene restituito alla funzione chiamante. La funzione chiamante può quindi riportare l'esecuzione alla funzione cedente e il suo stato verrà ripristinato al punto in cui è stata incontrata la 'resa' e l'esecuzione continuerà.


19
Qual è la differenza tra chiamare una funzione direttamente e cedere da un coroutine avvolgendo questa funzione in questo coroutine?
Ming Li,

3
Potrebbe essere meglio spiegare che questi due concetti non sono realmente "ortogonali" in questo contesto allora. Puoi sicuramente disegnare come i due concetti siano simili tra loro. L'idea di passare il controllo tra due o più cose è molto simile.
Steviejay

8
Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning.<- Questa è concorrenza. La parola che stai cercando è parallelismo.
Adam Arold,

@steviejay orthogonal = Not similar to each other?
tonix,

1
@tonix Mi è stato detto che orthogonalsignifica "indipendente l'uno dall'altro".
Rick,

77

Dalla sezione " " Programmazione in LuaCoroutines :

Una coroutine è simile a un thread (nel senso del multithreading): è una linea di esecuzione, con il suo stack, le sue variabili locali e il suo puntatore alle istruzioni; ma condivide variabili globali e soprattutto qualsiasi altra cosa con altre coroutine. La differenza principale tra thread e coroutine è che, concettualmente (o letteralmente, in una macchina multiprocessore), un programma con thread esegue più thread in parallelo. Le coroutine, d'altra parte, sono collaborative: in un dato momento, un programma con coroutine sta eseguendo solo una delle sue coroutine, e questa coroutine in esecuzione sospende la sua esecuzione solo quando richiede esplicitamente di essere sospesa.

Quindi il punto è: le coroutine sono "collaborative". Anche nel sistema multi-core, esiste un solo coroutine in esecuzione in un dato momento (ma più thread possono essere eseguiti in parallelo). Non c'è preventiva tra le coroutine, la coroutine in esecuzione deve rinunciare esplicitamente all'esecuzione.

Per " concurrency", puoi fare riferimento alla diapositiva di Rob Pike :

La concorrenza è la composizione di calcoli eseguiti in modo indipendente.

Pertanto, durante l'esecuzione della coroutine A, passa il controllo alla coroutine B. Quindi, dopo qualche tempo, la coroutine B passa il controllo alla coroutine A. Poiché esiste una dipendenza tra le coroutine e devono correre in tandem, quindi le due coroutine non sono concorrenti .


6
Le coroutine non vengono eseguite in modo indipendente. Si alternano, aspettando che l'altro faccia una parte del lavoro. Si coordinano attivamente tra loro. Questo è l'opposto della definizione di concorrenza di Rob Pikes.
Erick G. Hagstrom,

2
@ ErickG.Hagstrom: anche se non vengono eseguiti in modo indipendente, la logica di ogni coroutine può essere indipendente, giusto? Se è giusto, è proprio come un sistema operativo non preventivo in esecuzione su CPU a un core, un processo deve abbandonare la CPU per consentire l'esecuzione di altre attività.
Nan Xiao,

6
C'è una differenza tra rinunciare alla CPU per consentire l' esecuzione di qualche altra attività e dire a qualche altro processo specifico che è tempo di eseguire. Le coroutine fanno quest'ultimo. Non è indipendente in alcun senso.
Erick G. Hagstrom,

7
@ChrisClark Sono d'accordo con te. Le coroutine sono concorrenti. Ecco alcune citazioni da Wikipedia: le coroutine sono molto simili ai thread. Tuttavia, le coroutine sono multitasking in modo cooperativo, mentre i thread sono in genere preventivamente multitasking. Ciò significa che forniscono concorrenza ma non parallelismo .
smwikipedia,

3
E: il multitasking cooperativo, noto anche come multitasking non preventivo, è uno stile di multitasking informatico in cui il sistema operativo non avvia mai un cambio di contesto da un processo in esecuzione a un altro processo. Al contrario, i processi forniscono volontariamente il controllo periodicamente o quando sono inattivi o bloccati logicamente per consentire l'esecuzione simultanea di più applicazioni.
smwikipedia,

47

Trovo la maggior parte delle risposte troppo tecniche anche se si tratta di una domanda tecnica. Ho avuto difficoltà a capire il processo coroutine. In un certo senso lo capisco ma poi non lo capisco allo stesso tempo.

Ho trovato questa risposta qui molto utile:

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

Per citare da Idan Arye:

Per costruire sulla tua storia, la metterei in questo modo:

Inizi a guardare il cartone animato, ma è l'introduzione. Invece di guardare l'introduzione, passi al gioco ed entri nella lobby online, ma ha bisogno di 3 giocatori e solo tu e tua sorella ci siete dentro. Invece di aspettare che un altro giocatore si unisca a te, passa ai compiti e rispondi alla prima domanda. La seconda domanda ha un link a un video di YouTube che devi guardare. Lo apri e inizia a caricarsi. Invece di aspettare che si carichi, si torna al fumetto. L'introduzione è terminata, quindi puoi guardarla. Ora ci sono pubblicità - ma nel frattempo un terzo giocatore si è unito per passare al gioco E così via ...

L'idea è che non devi semplicemente cambiare le attività molto velocemente per far sembrare che stai facendo tutto in una volta. Utilizzi il tempo che aspetti che succeda qualcosa (IO) per fare altre cose che richiedono la tua attenzione diretta.

Sicuramente controlla il link, ci sono molti altri che non posso citare tutto.


6
Illustrazione molto semplice e diretta. +1 per questo.
Taslim Oseni,

ottima illustrazione. Ho costruito una storia simile - con la fila in attesa di ritirare un pacco. ma per oggi il tuo è molto più realistico, chi si mette in fila quando ci sono consegne door2door? Lol
apolak,

1
Questa è una spiegazione fantastica. Dalla citazione stessa, è super chiaro.
Farruh Habibullaev,

15

Coroutine è simile alla subroutine / thread. La differenza è che una volta che un chiamante ha invocato una subroutine / thread, non tornerà mai più alla funzione chiamante. Ma una coroutine può tornare al chiamante dopo aver eseguito alcuni frammenti di codice permettendo al chiamante di eseguire parte del proprio codice e tornare al punto coroutine in cui ha interrotto l'esecuzione e continuare da lì. vale a dire. Una coroutine ha più di un punto di entrata e di uscita


Non è così simile ai thread - che funzionano in modo indipendente e simultaneamente (nuclei separati in parallelo). Inoltre, il confronto delle subroutine non riesce nel senso che esistono più percorsi di esecuzione indipendenti e che non restituiscono risultati l'uno con l'altro.
Javavba,

11
  • Le coroutine sono grandi funzionalità disponibili in Kotlin Language
  • Le coroutine sono un nuovo modo di scrivere codice asincrono, non bloccante (e molto altro)
  • Coroutine sono fili leggeri. Un thread leggero significa che non è mappato sul thread nativo, quindi non richiede il cambio di contesto sul processore, quindi sono più veloci.
  • non viene mappato sul thread nativo
  • Le coroutine e i thread sono entrambi multitasking. Ma la differenza è che i thread sono gestiti dal sistema operativo e le coroutine dagli utenti.

Fondamentalmente, ci sono due tipi di Coroutine:

  1. stackless
  2. Stackful

Kotlin implementa coroutine impilabili - significa che le coroutine non hanno il proprio stack, quindi non mappano sul thread nativo.

Queste sono le funzioni per avviare la cerimonia:

launch{}

async{}

Puoi saperne di più da qui:

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

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


1
Buona risposta! Utile per gli sviluppatori Kotlin e Android.
Malwinder Singh,

5

In una nota diversa, nella geventlibreria python è una coroutinelibreria di rete basata che offre funzionalità simili a thread come richieste di rete asincrone, senza il sovraccarico di creare e distruggere thread. La coroutinelibreria utilizzata è greenlet.


2

Da Python Coroutine :

L'esecuzione delle coroutine di Python può essere sospesa e ripresa in molti punti (vedi coroutine). All'interno del corpo di una funzione coroutine, gli identificatori di attesa e asincrono diventano parole chiave riservate; attende espressioni, asincrono e asincrono con può essere usato solo nei corpi di funzioni coroutine.

Da Coroutine (C ++ 20)

Una coroutine è una funzione che può sospendere l'esecuzione da riprendere in seguito . Le coroutine sono impilate: sospendono l'esecuzione tornando al chiamante. Ciò consente il codice sequenziale che viene eseguito in modo asincrono (ad esempio per gestire I / O non bloccanti senza richiamate esplicite) e supporta anche algoritmi su sequenze infinite calcolate in modo pigro e altri usi.

Confronta con la risposta degli altri:

Secondo me, la parte successiva ripresa è una differenza fondamentale, proprio come quella di @ Twinkle.
Sebbene molti campi del documento siano ancora in corso di elaborazione, questa parte è simile alla maggior parte delle risposte, ad eccezione di @Nan Xiao

Le coroutine, d'altra parte, sono collaborative: in un dato momento, un programma con coroutine sta eseguendo solo una delle sue coroutine, e questa coroutine in esecuzione sospende la sua esecuzione solo quando richiede esplicitamente di essere sospesa.

Dal momento che è citato dal Programma in Lua, forse è legato alla lingua (non ha familiarità con Lua al momento), non tutti i documenti menzionano l' unica parte.

La relazione concomitante:
esiste una parte "Esecuzione" delle Coroutine (C ++ 20). Troppo lungo per essere citato qui.
Oltre al dettaglio, ci sono diversi stati.

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 

come il commento di @Adam Arold nella risposta di @ user217714. È concorrenza.
Ma è diverso dal multithreading. da std :: thread

I thread consentono l'esecuzione simultanea di più funzioni. I thread iniziano l'esecuzione immediatamente dopo la costruzione dell'oggetto thread associato (in attesa di eventuali ritardi di pianificazione del sistema operativo), a partire dalla funzione di livello superiore fornita come argomento del costruttore. Il valore restituito della funzione di livello superiore viene ignorato e se termina generando un'eccezione, viene chiamato std :: terminate. La funzione di livello superiore può comunicare il suo valore di ritorno o un'eccezione al chiamante tramite std :: promise o modificando le variabili condivise (che possono richiedere la sincronizzazione, vedere std :: mutex e std :: atomic)

Dal momento che è in concorrenza, funziona come il multithreading soprattutto quando l'attesa è inevitabile (dal punto di vista del sistema operativo), è anche per questo che confonde.


1

Un coroutine è un tipo speciale di sottoprogramma. Piuttosto che la relazione master-slave tra un chiamante e un sottoprogramma chiamato esistente con i sottoprogrammi convenzionali, chiamante e coroutine sono più equi.

  • Un coroutine è un sottoprogramma che ha più voci e le controlla da sé - supportato direttamente in Lua

  • Chiamato anche controllo simmetrico: il chiamante e le coroutine chiamate sono su una base più equa

  • Una chiamata coroutine è chiamata resume

  • Il primo curriculum di una coroutine è al suo inizio, ma le chiamate successive entrano nel punto immediatamente successivo all'ultima istruzione eseguita nella coroutine

  • Le coroutine si riprendono ripetutamente, forse per sempre

  • Le coroutine forniscono l'esecuzione quasi simultanea di unità di programma (le coroutine); la loro esecuzione è interfogliata, ma non sovrapposta

Esempio 1 Esempio 2


1

Trovo che una spiegazione da questo link sia piuttosto semplice. Nessuna di queste risposte tenta di spiegare la concorrenza rispetto al parallelismo, tranne l'ultimo punto elenco in questa risposta .

  1. che cos'è concorrente (programma)?

citato da "programmazione Erlang", di Joe Armstrong, il leggendario:

un programma simultaneo può essere eseguito potenzialmente più velocemente su un computer parallelo.

  • un programma concorrente è un programma scritto in un linguaggio di programmazione concorrente. Scriviamo programmi simultanei per motivi di prestazioni, scalabilità o tolleranza agli errori.

  • un linguaggio di programmazione concorrente è un linguaggio che ha costrutti di linguaggio espliciti per la scrittura di programmi concorrenti. Questi costrutti sono parte integrante del linguaggio di programmazione e si comportano allo stesso modo su tutti i sistemi operativi.

  • un computer parallelo è un computer che ha diverse unità di elaborazione (CPU o core) che possono essere eseguite contemporaneamente.

Quindi la concorrenza non è la stessa del parallelismo. È ancora possibile scrivere programmi simultanei su un computer single-core. Il programmatore di condivisione del tempo ti farà sentire il programma in esecuzione contemporaneamente.

Il programma concorrente ha il potenziale per funzionare in parallelo in un computer parallelo ma non è garantito . Il sistema operativo può darti solo un core per eseguire il tuo programma.

Pertanto, la concorrenza è un modello software di un programma simultaneo che non significa che il programma possa essere eseguito in parallelo fisicamente.

  1. coroutine e concorrenza

La parola "coroutine" è composta da due parole: "co" (cooperativa) e "routine" (funzioni).

un. raggiunge la concorrenza o il parallelismo?

Per essere semplici, discutiamolo su un computer single-core .

La concorrenza è raggiunta da time-share dal sistema operativo. Un thread esegue il suo codice nei suoi intervalli di tempo assegnati sul core della CPU. Può essere annullato dal sistema operativo. Può anche dare il controllo al sistema operativo.

Un coroutine, d'altra parte, fornisce il controllo a un altro coroutine all'interno del thread, non al sistema operativo. Quindi tutte le coroutine all'interno di un thread sfruttano ancora l'intervallo di tempo per quel thread senza cedere il core della CPU ad altri thread gestiti dal sistema operativo.

Pertanto, si può pensare alla coroutine che raggiunge le condivisioni del tempo da parte dell'utente e non dal sistema operativo (o quasi-parallelismo). Le coroutine vengono eseguite sullo stesso core assegnato al thread che esegue quelle coroutine.

Coroutine raggiunge il parallelismo? Se è un codice associato alla CPU, no. Come le multiproprietà, ti fa sentire che corrono in parallelo ma le loro esecuzioni sono intercalate non sovrapposte. Se è associato a IO, sì, ottiene parallelo dall'hardware (IO Device) e non dal tuo codice.

b. la differenza con la chiamata di funzione?

inserisci qui la descrizione dell'immagine

Come mostra la foto, non è necessario chiamare returnper cambiare controllo. Può cedere senza return. Una coroutine salva e condivide lo stato nel frame della funzione corrente (stack). Quindi è molto più leggero della funzione poiché non è necessario salvare registri e variabili locali per impilare e riavvolgere lo stack di chiamate quando call ret.


0

Espanderò sulla risposta di @ user21714. Le coroutine sono percorsi di esecuzione indipendenti che non possono essere eseguiti contemporaneamente. Dipendono da un controller, ad esempio una pythonlibreria di controller, per gestire il passaggio tra questi percorsi. Ma affinché ciò funzioni, le coroutine stesse devono invocare yieldo strutture simili che consentano di mettere in pausa la loro esecuzione.

I thread invece sono in esecuzione su risorse di calcolo indipendenti e in parallelo tra loro. Poiché si trovano su risorse diverse, non è necessario invocare il rendimento per consentire agli altri percorsi di esecuzione di procedere.

Puoi vedere questo effetto avviando un programma multihread - ad esempio jvmun'applicazione - in cui core i7sono utilizzati tutti e otto i tuoi core hyperthread: potresti vedere un utilizzo del 797% in Activity Monitoro Top. Invece quando si esegue un pythonprogramma tipico - anche uno con coroutineso python threading- l'utilizzo verrà massimizzato al 100%. Cioè una macchina hyperthread.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.