GO - Goroutine e concorrenza

1

Sfondo:

Threads use pre-emptive scheduling, whereas fibers use cooperative scheduling.

With threads: the current execution path may be interrupted or preempted at any time This means that for threads, data integrity is a big issue because one thread may be stopped in the middle of updating a chunk of data, leaving the integrity of the data in a bad or incomplete state. This also means that the operating system can take advantage of multiple CPUs and CPU cores by running more than one thread at the same time and leaving it up to the developer to guard data access.

Using C,

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

Using threads, application may have Concurrency,

Properties of Concurrency:

1) Multiple actors

2) Shared resource

3) Rules to access(Atomic/Conditional synchronization)

With fibers: the current execution path is only interrupted when the fiber yields execution This means that fibers always start and stop in well-defined places, so data integrity is much less of an issue. Also, because fibers are often managed in the user space, expensive context switches and CPU state changes need not be made, making changing from one fiber to the next extremely efficient. On the other hand, since no two fibers can run at exactly the same time, just using fibers alone will not take advantage of multiple CPUs or multiple CPU cores.

In Win32, a fiber is a sort of user-managed thread. A fiber has its own stack and its own instruction pointer etc., but fibers are not scheduled by the OS: you have to call SwitchToFiber explicitly. Threads, by contrast, are pre-emptively scheduled by the operation system.

So roughly speaking a fiber is a thread that is managed at the application/runti me level rather than being a true OS thread.

Using C,

void __stdcall MyScheduler(void *param){
  ....
}

LPVOID *FiberScheduler = CreateFiber(0, MyScheduler, NULL);

Why fibers?

OS threads give us everything we want, but for a heavy performance penalty: switching between threads involves jumping back and forth from user to kernel mode, possibly even across address space boundaries. These are expensive operations partly because they cause TLB flushes, cache misses and CPU pipelining havoc: that’s also why traps and syscalls can be orders of magnitude slower than regular procedure calls.

In addition, the kernel schedules threads (i.e. assigns their continuation to a CPU core) using a general-purpose scheduling algorithm, which might take into account all kinds of threads, from those serving a single transaction to those playing an entire video.

Fibers, because they are scheduled at the application layer, can use a scheduler that is more appropriate for their use-case. As most fibers are used to serve transactions, they are usually active for very short periods of time and block very often. Their behavior is often to be awakened by IO or another fiber, run a short processing cycle, and then transfer control to another fiber (using a queue or another synchronization mechanism).Such behavior is best served by a scheduler employing an algorithm called “work-stealing”;When fibers behave this way, work-stealing ensures minimal cache misses when switching between fibers.

La fibra non sfrutta la potenza di più core, perché ciò che sa è il sistema operativo, processo a thread singolo.

In GO, invochiamo le goroutine usando go keyword

func main(){
  go f() // f runs as new go routine
  f()
}

Domanda:

1) La routine GO ( f ) è una fibra programmata non preventivamente dal runtime GO, nello spazio utente?

2) In caso affermativo, la situazione di concorrenza si verifica nell'ambiente GO?

3) GO supporta l'API per il thread a livello di sistema operativo?

    
posta overexchange 31.01.2017 - 06:06
fonte

2 risposte

1

Domanda n. 1: Non proprio

Le goroutine sono un po 'strane. Sono in qualche modo simili alle fibre, ma anche in qualche modo simili ai fili.

  • Potrebbero essere preventivati.
  • Potrebbero essere simultanei.
  • Potrebbero condividere risorse.
  • Spesso bloccano una coda (canale).
  • Hanno i propri stack.
  • Non sono programmati direttamente dal sistema operativo, ma dal runtime golang.

Il runtime golang di solito inizia per default a GOMAXPROCS thread e pianifica le tue goroutine tra di loro. Su qualsiasi thread specificato, una goroutine verrà eseguita fino al completamento o finché non si bloccherà su un canale.

Questo significa che puoi pensare alle goroutine come fibre condivise tra i fili.

Questo significa che puoi pensare alle goroutine che non accedono allo stato globale come pensi alle fibre. Ma per le goroutine che accedono allo stato globale, è necessario trattarle come dei thread.

Domanda n. 2:

Devi essere attento quando accedi allo stato globale!

Tuttavia, il meccanismo di comunicazione predefinito, i canali, sincronizza l'accesso alle risorse condivise, che facilita la programmazione concorrente in Go da molto.

Domanda n. 3: Non nella libreria standard

Se lo desideri, puoi avviare i thread scrivendo una libreria in C per Go che ti consente di accedere alle funzioni del thread del sistema operativo sottostante (come pthread_create ).

Tuttavia, dubito strongmente che potresti usare goroutine e canali sui thread creati in questo modo, dato che lo scheduler runtime golan non ne ha conoscenza.

Ciò potrebbe anche causare problemi con chiamate ad altre librerie (come la libreria standard!) che presuppongono l'accesso a goroutine e canali.

In conclusione, non penso che creare e gestire direttamente thread in Go sia una buona idea.

    
risposta data 31.01.2017 - 13:19
fonte
5

Golang Goroutines sono una struttura per compilatori. Concettualmente Goroutine e fibre sono metodi cooperativi di multitasking rispetto all'ambiente. Le fibre sono un concetto a livello di sistema operativo, mentre goroutine è un concetto a livello di compilatore.

Le goroutine possono corrispondere a una specifica di fibra (sembrano esserci molte) ma non necessariamente fibre nel senso più stretto. Infatti una goroutine può essere distribuita su più thread come deciso dallo schedulatore.

  1. Per la spiegazione fornita della fibra. Sì, le Goroutine potrebbero essere chiamate come un'implementazione delle specifiche della fibra da te proposte.

  2. Dovresti idealmente pensare in termini di CSP piuttosto che di concorrenza.

Comunicare i processi sequenziali (CSP) è il modello di concorrenza di go e le goroutine lo consentono. Isolando la componente goroutine e pensando alla concorrenza è un po 'fuori dalla prospettiva di Golang.

Sei incoraggiato a utilizzare i canali per mantenere il flusso di dati e non fare affidamento su altri meccanismi di sincronizzazione (come dice Pike, non comunicare condividendo, condividendo comunicando). Sebbene tu possa ancora usare i mutex se lo desideri, ma non puoi ancora creare discussioni da solo.

In effetti, l'approccio di go alla concorrenza è più vicino a erlang rispetto ad altri linguaggi tradizionali e alle relative implementazioni.

  1. Per lo stesso motivo di cui sopra. Go non consente di creare direttamente thread (è possibile generare più processi, però). Sei incoraggiato a utilizzare solo le goroutine con i canali per evitare che le confusioni usino approcci multitasking multipli.

Go utilizza lo stesso numero di thread del sistema operativo impostato dalla variabile di ambiente GOMAXPROCS (che come GO1.5 è impostato sul numero di core della CPU).

Ecco una bella discussione su di esso

    
risposta data 31.01.2017 - 07:40
fonte

Leggi altre domande sui tag