Domanda

Il concetto di coroutine sembra molto interessante, ma non so se ha senso in un ambiente produttivo reale? Quali sono i casi d'uso per le coroutine, che possono essere risolti più eleganti, più semplici o più efficienti come con altri metodi?

È stato utile?

Soluzione

Le vere coroutine richiedono il supporto dei tuoi strumenti: devono essere implementate dal compilatore e supportate dal framework sottostante.

Un esempio reale di Coroutine si trova con il "rendimento rendimento" parola chiave fornita in C # 2.0, che consente di scrivere un metodo che restituisce più valori per il ciclo.

Il " rendimento rendimento " presenta tuttavia delle limitazioni: l'implementazione utilizza una classe helper per acquisire lo stato e supporta solo un caso specifico di coroutine come generatore (iteratore).

Nel caso più generale, il vantaggio delle Coroutine è che rendono alcuni calcoli basati sullo stato molto più facili da esprimere e più comprensibili - implementare una macchina a stati come un insieme di coroutine può essere più elegante di approcci più comuni . Tuttavia, ciò richiede supporto e strumenti che non esistono ancora in C # o Java.

Altri suggerimenti

Alcune buone risposte che descrivono cosa sono le coroutine.

Ma per un caso d'uso reale. Prendi un web server. Ha più connessioni simultanee e desidera pianificare la lettura e la scrittura di tutte.

Questo può essere implementato usando le coroutine. Ogni connessione è un coroutine che legge / scrive una piccola quantità di dati, quindi "cede". controllo allo scheduler, che passa alla successiva routine (che fa la stessa cosa) mentre passiamo attraverso tutte le connessioni disponibili.

Molti, ad esempio:

grep TODO *.c *.h | wc -l

La pipeline sopra è esattamente un coroutine: il comando grep genera una sequenza di linee che vanno in un buffer, il comando wc li mangia su " ;; se il buffer si riempie, grep " blocca " fino allo svuotamento del buffer e se il buffer è vuoto, il comando wc attende un nuovo input.

Il vantaggio delle coroutine è che ora vengono spesso utilizzate in schemi più vincolati, come i generatori di Python menzionati, o come pipeline.

Se vuoi guardarli di più, consulta gli articoli di Wikipedia, in particolare su coroutine e iteratori .

So che sono trascorsi quasi 5 anni da quando è stata posta la domanda, ma sono sorpreso che nessuno abbia menzionato il caso d'uso di giochi in cui le coroutine sono usate molto per essenzialmente dividere il tempo in un calcolo.

Per mantenere un frame rate costante in un gioco, diciamo 60 fps, hai circa 16.6ms per eseguire il codice in ogni frame. Ciò include la simulazione fisica, l'elaborazione dell'input, il disegno / pittura.

Supponiamo che il tuo metodo sia eseguito in ogni frame. Se il tuo metodo impiega molto tempo e finisce per estendersi su più frame, scaglionerai il resto del calcolo nel loop del gioco, il che si tradurrà in un utente che vedrà "jank". (un improvviso calo del frame rate).

Ciò che le coroutine ti permettono di fare è in qualche modo dividere questo calcolo in modo che funzioni un po 'in ogni frame.

Perché ciò accada, le coroutine essenzialmente consentono al metodo di "cedere". il calcolo ritorna al "chiamante" (in questo caso il loop di gioco) in modo che alla successiva chiamata il metodo riprenda da dove era stato interrotto.

Le coroutine sono utili per implementare modelli di produttori / consumatori.

Ad esempio, Python ha introdotto le coroutine in una funzione linguistica chiamata generatori , che era destinato a semplificare l'implementazione degli iteratori.

Possono anche essere utili per implementare il multitasking cooperativo, in cui ogni attività è un coroutine che cede a uno scheduler / reattore.

Le coroutine possono essere utili ogni volta che un sistema ha due o più parti di codice la cui rappresentazione più naturale sarebbe una serie sequenziale di passaggi che comportano molta attesa.

Ad esempio, si consideri un dispositivo che ha un'interfaccia utente LCD e tastiera e un modem, e deve usare il modem per chiamare periodicamente e riportare il suo stato indipendentemente da ciò che sta facendo l'utente sulla tastiera. Il modo migliore per scrivere l'interfaccia utente potrebbe essere quello di utilizzare funzioni come " input_numeric_value (& amp; CONV_SPEED_FORMAT, & amp; conveyor_speed); " che tornerà quando un utente ha inserito un valore e il modo migliore per gestire la comunicazione potrebbe essere utilizzare funzioni come " wait_for_carrier (); " che tornerà quando l'unità si è connessa o ha determinato che non lo farà.

Senza coroutine, il sottosistema UI o il sottosistema modem dovrebbero essere implementati utilizzando una macchina a stati. L'uso di coroutine consente di scrivere entrambi i sottosistemi nello stile più naturale. Nota che è importante che nessuno dei due sottosistemi vada mai molto a lungo senza mettere le cose in un "coerente". dichiarare e chiamare yield (), né chiama yield () senza mettere le cose in una "coerente" dichiarare prima, ma di solito non è difficile soddisfare tali vincoli.

Si noti che mentre si può usare il multitasking completo, ciò richiede l'uso di blocchi in tutto il luogo ogni volta che lo stato condiviso viene modificato. Dal momento che il commutatore coroutine non cambierà mai le cose tranne che alle chiamate yield (), entrambe le routine possono modificare liberamente lo stato condiviso fintanto che assicura che tutto sia in ordine prima del prossimo rendimento ed è preparato per l'altra routine per modificare lo stato " , durante " il rendimento ().

Come esempio più specifico nella linea di produttori / consumatori, qualcosa di semplice come l'umile programma di reportistica batch potrebbe effettivamente utilizzare le routine.

Il suggerimento chiave per questo esempio è avere un lavoro non banale per consumare i dati di input (ad es. analizzare i dati o accumulare addebiti e pagamenti su un account) e un lavoro non banale per produrre l'output. Quando hai queste caratteristiche:

  • È facile organizzare / comprendere il codice lato input se puoi " emettere " unità di lavoro in vari luoghi.
  • È anche facile organizzare / comprendere il codice sul lato output se è in grado di "catturare" la prossima unità di lavoro in una struttura di controllo nidificata.

quindi le coroutine e le code sono entrambe belle tecniche da avere a tua disposizione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top