2009-12-20 15 views

risposta

58

Le coroutine sono una forma di elaborazione sequenziale: solo una è in esecuzione in un dato momento (proprio come le subroutine procedure AKA funzioni AKA - semplicemente passano il testimone l'uno con l'altro in modo più fluido).

I thread sono (almeno concettualmente) una forma di elaborazione simultanea: più thread possono essere eseguiti in qualsiasi momento. (Tradizionalmente, su macchine single-core, single-core, la concorrenza è stata simulata con un po 'di aiuto dal sistema operativo - oggigiorno, dal momento che così tante macchine sono multi-CPU e/o multi-core, i thread saranno de facto contemporaneamente, non solo "concettualmente").

7

Dipende dalla lingua che si sta utilizzando. Ad esempio in Lua they are the same thing (il tipo di variabile di una coroutine è chiamato thread).

Di solito, sebbene le coroutine implementino il cedimento volontario in cui (voi) il programmatore decide dove immettere yield, ovvero dare il controllo a un'altra routine.

I thread invece vengono gestiti automaticamente (arrestati e avviati) dal sistema operativo e possono anche essere eseguiti contemporaneamente su CPU multicore.

11

In una parola: prelazione. Le coroutine si comportano come i giocolieri che continuano a consegnarsi l'un l'altro a punti ben provati. I thread (thread veri) possono essere interrotti in quasi tutti i punti e ripresi in seguito. Ovviamente, questo porta con sé tutti i tipi di problemi di conflitto di risorse, da qui il famigerato GIL - Global Interpreter Lock di Python.

Molte implementazioni di thread sono in realtà più simili a coroutine.

74

Prima lettura:Concurrency vs Parallelism - What is the difference?

concorrenza è la separazione dei compiti per fornire interleaved esecuzione. Parallelismo è l'esecuzione simultanea di più pezzi di lavoro al fine di aumentare la velocità. - https://github.com/servo/servo/wiki/Design

Risposta breve: Con fili, il sistema operativo in esecuzione commuta fili preventivamente secondo il proprio programmatore, che è un algoritmo nel kernel del sistema operativo. Con le coroutine, il programmatore e il linguaggio di programmazione determinano quando cambiare le coroutine; in altre parole, i compiti sono cooperativamente multitasking sospendendo e riprendendo le funzioni sui set point, tipicamente (ma non necessariamente) all'interno di un singolo thread.

Risposta lunga: In contrasto fili, che sono preventivamente programmato dal sistema operativo, interruttori coroutine sono cooperativa, cioè il programmatore (e possibilmente il linguaggio di programmazione e la sua esecuzione) controlla quando un interruttore avverrà.

In contrasto con fili, che sono preventivo, interruttori coroutine sono cooperative (controlli programmatore quando un interruttore accadrà). Il kernel non è coinvolto negli switch di coroutine. - http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

Un linguaggio che supporti discussioni native in grado di eseguire le sue discussioni (thread utente) sul thread del sistema operativo (kernel thread). Ogni processo ha almeno un thread del kernel. I thread del kernel sono come i processi, tranne che condividono lo spazio di memoria nel loro processo proprietario con tutti gli altri thread in quel processo. Un processo "possiede" tutte le risorse assegnate, come memoria, handle di file, socket, handle di dispositivo, ecc. E queste risorse sono condivise tra i thread del kernel.

Lo scheduler del sistema operativo fa parte del kernel che esegue ciascun thread per un determinato periodo di tempo (su un singolo processore). Lo schedulatore alloca il tempo (timelicing) per ogni thread e se il thread non è terminato entro quel tempo, lo scheduler lo pre-impegna (lo interrompe e passa a un altro thread). Più thread possono essere eseguiti in parallelo su una macchina multiprocessore, poiché ogni thread può essere (ma non deve necessariamente essere) pianificato su un processore separato.

Su una macchina a processore singolo, i thread vengono moltiplicati e vengono preimpostati (commutati tra) rapidamente (su Linux il timeslice predefinito è 100 ms) che li rende simultanei. Tuttavia, non possono essere eseguiti in parallelo (simultaneamente), poiché un processore single-core può eseguire solo una cosa alla volta.

coroutine e/o generatori possono essere utilizzati per implementare funzioni cooperative. Invece di essere eseguiti su thread del kernel e programmati dal sistema operativo, vengono eseguiti in un singolo thread fino a quando non producono o terminano, cedendo ad altre funzioni determinate dal programmatore. Le lingue con i generatori , come Python e ECMAScript 6, possono essere utilizzate per creare coroutine. Async/await (visto in C#, Python, ECMAscript 7, Rust) è un'astrazione costruita sulla base di funzioni generatrici che generano futures/promesse.

In alcuni contesti, coroutine possono riferirsi alle funzioni stackful mentre generatori possono riferirsi alle funzioni Stackless.

Fibre, fili leggeri e fili verdi sono altri nomi per coroutine o cose coroutine-like. A volte possono sembrare (tipicamente di proposito) più simili ai thread del sistema operativo nel linguaggio di programmazione, ma non vengono eseguiti in parallelo come veri thread e funzionano invece come le coroutine. (Potrebbero esserci particolarità o differenze tecniche più specifiche tra questi concetti a seconda della lingua o dell'implementazione.)

Ad esempio, Java ha "fili verdi"; si trattava di thread pianificati dalla Java virtual machine (JVM) anziché in modo nativo sui thread del kernel del sistema operativo sottostante. Questi non sono stati eseguiti in parallelo o si avvalgono di più processori/core, poiché ciò richiederebbe un thread nativo! Dal momento che non erano stati programmati dal sistema operativo, erano più simili alle coroutine rispetto ai thread del kernel. I fili verdi sono ciò che Java ha usato fino a quando i thread nativi sono stati introdotti in Java 1.2.

I thread consumano risorse. Nella JVM, ogni thread ha il proprio stack, in genere 1 MB di dimensioni. 64k è la quantità minima di spazio di stack consentita per thread nella JVM. La dimensione dello stack di thread può essere configurata sulla riga di comando per JVM. Nonostante il nome, i thread non sono gratuiti, a causa delle risorse di utilizzo come ogni thread che necessita del proprio stack, dell'archiviazione locale dei thread (se presente) e del costo della schedulazione del thread/commutazione di contesto/invalidazione della cache della CPU.Questo è uno dei motivi per cui le coroutine sono diventate popolari per le applicazioni critiche dal punto di vista delle prestazioni e altamente concomitanti.

Mac OS consentirà solo un processo di allocare circa 2000 thread e Linux alloca 8 MB di stack per thread e consentirà solo il numero di thread che si adatta alla RAM fisica.

Quindi, i fili sono il peso più pesante (in termini di utilizzo della memoria e tempo di commutazione del contesto), quindi coroutine e infine i generatori sono il peso più leggero.

+1

+1, ma questa risposta potrebbe beneficiare di alcuni riferimenti. – kojiro

+1

I fili verdi sono qualcosa di diverso rispetto alle coroutine. non lo sono?Anche le fibre hanno alcune differenze. vedi http://programmers.stackexchange.com/questions/254140/is-there-a-difference-between-fibers-coroutines-and-green-threads-and-if-that-i – penguin

43

Circa 7 anni in ritardo, ma le risposte qui mancano del contesto su co-routines vs thread. Perché le coroutine ricevono così tanta attenzione negli ultimi tempi e quando le utilizzerei rispetto alle filettature ?

Prima di tutto se coroutine eseguiti concomitanza (mai in parallelo ), perché qualcuno li preferirebbe nel corso discussioni?

La risposta è che coroutine grado di fornire un elevato livello di concorrenzacon molto poco overhead. Generalmente in un ambiente con thread si hanno al massimo 30-50 thread prima che la quantità di overhead sprecato effettivamente programmando questi thread (dallo scheduler di sistema) in modo significativo da taglia nel tempo in cui i thread effettivamente funzionano.

Ok con i thread è possibile avere il parallelismo, ma non troppo il parallelismo, non è ancora meglio di una co-routine in esecuzione in un singolo thread? Beh, non necessariamente. Ricordare che una co-routine può ancora fare concorrenza senza sovraccarico dello scheduler - semplicemente gestisce il cambio di contesto stesso.

Ad esempio se si ha una routine di lavoro e si esegue un'operazione che si bloccherà per un po 'di tempo (ad esempio una richiesta di rete), con un co-routine è possibile passare immediatamente a un'altra routine senza il sovraccarico di lo scheduler di sistema in questa decisione - sì, il programmatore deve specificare quando è possibile cambiare le co-routine.

Con un sacco di routine che eseguono lavori molto piccoli e si commutano volontariamente l'uno con l'altro, si è raggiunto un livello di efficienza che nessun programmatore potrebbe mai sperare di ottenere. Ora puoi far lavorare migliaia di coroutine insieme a decine di thread.

Perché le routine ora passare tra di loro un pre-determinati punti è ora possibile anche evitare il blocco su strutture dati condivise (perché si sarebbe mai dire il codice per passare ad un altro coroutine nel bel mezzo di una sezione critica)

Un altro vantaggio è l'utilizzo della memoria molto più basso. Con il modello a thread, ogni thread deve allocare il proprio stack e quindi l'utilizzo della memoria cresce in modo lineare con il numero di thread che si hanno. Con le co-routines, il numero di routine che hai non ha una relazione diretta con l'utilizzo della memoria.

E, infine, coroutine stanno ricevendo un sacco di attenzione perché in alcuni linguaggi di programmazione (come Python) tuoi thread non possono essere eseguiti in parallelo in ogni caso - corrono in concomitanza proprio come coroutine, ma senza la poca memoria e libera scheduling overhead.

+2

Come passare ad un'altra compito in coroutine quando incontriamo un'operazione di blocco? –

+0

Il modo in cui si passa a un'altra attività è che tutte le operazioni di blocco siano effettivamente eseguite in modo asincrono. Ciò significa che devi evitare di utilizzare qualsiasi operazione che potrebbe effettivamente bloccare e utilizzare solo operazioni che non supportano il blocco quando utilizzate nel tuo sistema di coroutine. L'unico modo per aggirare questo è avere coroutine supportate dal kernel, come ad esempio UMS su Windows, dove salta nello scheduler ogni volta che il "thread" UMS blocca su un syscall. – retep998

Problemi correlati