Le piscine goroutine di go-lang sono solo fili verdi?

42

Il commentatore qui offre le seguenti critiche sui thread verdi:

I was initially sold on the N:M model as a means of having event driven programming without the callback hell. You can write code that looks like pain old procedural code but underneath there's magic that uses userspace task switching whenever something would block. Sounds great. The problem is that we end up solving complexity with more complexity. swapcontext() and family are fairly strait-forward, the complexity comes from other unintended places.

All of a sudden you're forced to write a userspace scheduler and guess what it's really hard to write a scheduler that's going to do a better job that Linux's schedules that has man years of efforts put into it. Now you want your schedule to man N green threads to M physical threads so you have to worry about synchronization. Synchronization brings performance problems so you start now you're down a new lockless rabbit hole. Building a correct highly concurrent scheduler is no easy task.

Un'altra critica è qui :

A single process faking multiple threads has a lot of problems. One of them is that all the faked threads stall on any page fault.

La mia domanda è - sono le goroutine di go-lang (per un pool predefinito) solo thread verdi? Se è così, rispondono alle critiche sopra?

    
posta hawkeye 30.12.2013 - 04:58
fonte

1 risposta

62

Sono solo un utente casuale, quindi prendi le seguenti cose con un pizzico di sale.

Wikipedia definisce thread verdi come "thread pianificati da una macchina virtuale (VM) anziché nativamente dal sottostante sistema operativo". I thread verdi emulano gli ambienti con multithreading senza fare affidamento su alcuna funzionalità del sistema operativo nativo e vengono gestiti nello spazio utente anziché nello spazio del kernel, consentendo loro di lavorare in ambienti che non hanno il supporto del thread nativo.

Go (o più esattamente le due implementazioni esistenti) è un linguaggio che produce solo codice nativo - non usa una VM. Inoltre, lo scheduler nelle attuali implementazioni di runtime si basa su thread a livello di sistema operativo (anche quando GOMAXPROCS = 1). Quindi penso che parlare di thread verdi per il modello Go sia un po 'offensivo.

Go persone hanno coniato il termine goroutine soprattutto per evitare la confusione con altri meccanismi di concorrenza (come coroutine o thread o processi leggeri).

Ovviamente, Go supporta un modello di threading M: N, ma sembra molto più vicino al modello di processo di Erlang, che al modello di thread verde di Java.

Ecco alcuni vantaggi del modello Go rispetto ai thread verdi (come implementato nella JVM iniziale):

  • È possibile utilizzare in modo efficace più core o CPU, in modo trasparente per lo sviluppatore. Con Go, lo sviluppatore dovrebbe occuparsi della concorrenza. Il runtime Go si occuperà del parallelismo. Le implementazioni dei thread verdi Java non sono state ridimensionate su più core o CPU.

  • Le chiamate di sistema e C non bloccano lo scheduler (tutte le chiamate di sistema, non solo quelle che supportano I / O multiplex nei loop di eventi). Implementazioni di thread verdi potrebbero bloccare l'intero processo quando è stata effettuata una chiamata di sistema di blocco.

  • Copia o stack segmentati. In Go, non è necessario fornire una dimensione massima dello stack per la goroutine. Lo stack cresce in modo incrementale quando necessario. Una conseguenza è che una goroutine non richiede molta memoria (4KB-8KB), quindi un numero enorme di essi può essere felicemente generato. L'utilizzo di Goroutine può quindi essere pervasivo.

Ora, per rispondere alle critiche:

  • Con Go, non è necessario scrivere uno scheduler userspace: è già fornito con il runtime. È un software complesso, ma è il problema degli sviluppatori Go, non degli utenti Go. Il suo utilizzo è trasparente per gli utenti di Google. Tra gli sviluppatori Go, Dmitri Vyukov è un esperto di programmazione lockfree / waitfree, e sembra essere particolarmente interessato ad affrontare gli eventuali problemi di prestazioni dello scheduler. L'attuale implementazione dello scheduler non è perfetta, ma migliorerà.

  • La sincronizzazione porta problemi di prestazioni e complessità: questo è parzialmente vero anche con Go. Ma si noti che il modello Go cerca di promuovere l'uso di canali e una scomposizione pulita del programma in concurrent goroutines per limitare la complessità della sincronizzazione (cioè condividere i dati comunicando, invece di condividere la memoria per comunicare). A proposito, l'implementazione Go di riferimento fornisce una serie di strumenti per affrontare i problemi di prestazioni e concorrenza, come un profiler , e un rilevatore di corse .

  • Per quanto riguarda l'errore di pagina e "falsi thread multipli", si noti che Go può pianificare goroutine su più thread di sistema. Quando un thread è bloccato per qualsiasi motivo (errore di pagina, blocco delle chiamate di sistema), non impedisce agli altri thread di continuare a pianificare ed eseguire altre goroutine. Ora, è vero che un errore di pagina bloccherà il thread del SO, con tutte le goroutine programmate su questo thread. Tuttavia, in pratica, la memoria heap di Go non dovrebbe essere scambiata. Questo sarebbe lo stesso in Java: i linguaggi raccolti con garbage collection non adattano molto bene la memoria virtuale. Se il tuo programma deve gestire l'errore di pagina in modo aggraziato, probabilmente perché deve gestire una memoria fuori dal mucchio. In tal caso, il wrapping del codice corrispondente con le funzioni di accesso C risolverà semplicemente il problema (poiché ancora una volta C chiama o blocca le chiamate di sistema non blocca mai lo scheduler di Go runtime).

Quindi IMO, le goroutine non sono thread verdi, e la lingua Go e l'implementazione attuale affronta principalmente queste critiche.

    
risposta data 30.12.2013 - 19:42
fonte

Leggi altre domande sui tag