2014-07-06 7 views
41

In che modo altre goreutine possono continuare ad eseguire mentre si richiama un syscall? (quando si utilizza GOMAXPROCS = 1)
Per quanto ne so, quando si richiama un syscall il thread lascia il controllo fino a quando non viene restituito syscall. Come si può raggiungere questa concorrenza senza creare un thread di sistema per goroutine di blocking-on-syscall?Come funzionano le goroutine? (o: goroutines e relazione sui thread del sistema operativo)

Dal documentation:

Goroutines

Si chiamano goroutines perché gli attuali termini-fili, coroutine, processi, e così via, trasmettere connotazioni imprecisi. A goroutine ha un modello semplice: è una funzione che esegue contemporaneamente con altre goroutine nello stesso spazio di indirizzamento. È leggero, che costa poco più dell'allocazione dello spazio di stack. E gli stack iniziano in piccolo, quindi sono economici e crescono allocando (e liberando) lo storage dell'heap come richiesto.

Le goroutine vengono multiplexate su più thread del sistema operativo, quindi se si deve bloccare , ad esempio mentre si attende l'I/O, altri continuano a funzionare. Il loro design nasconde molte delle complessità della creazione dei thread e della gestione di .

+0

Questo post del blog di Dave Cheney's REALMENTE spiega https://dave.cheney.net/2015/08/08/performance-without-the-event-loop –

risposta

25

Se una goroutine sta bloccando, il runtime avvierà un nuovo thread del sistema operativo per gestire le altre goroutine fino a quando il blocco non interrompe il blocco.

Riferimento: https://groups.google.com/forum/#!topic/golang-nuts/2IdA34yR8gQ

+1

In realtà multiplexe diverse goroutine in thread (1+ goroutine per thread). Se uno blocca, un altro viene commutato per essere eseguito sullo stesso thread. Questa operazione richiede solo 3 registri per cambiare, ecco perché è così leggera. – Zarkopafilis

10

Non è possibile. C'è solo 1 goroutine che può essere in esecuzione in un momento in cui GOMAXPROCS = 1, indipendentemente dal fatto che una goroutine stia effettuando una chiamata di sistema o qualcos'altro.

Tuttavia, la maggior parte delle chiamate di sistema bloccanti, come l'I/O socket, in attesa di un timer non vengono bloccate su una chiamata di sistema quando eseguite da Go. Sono multiplexati dal runtime Go su epoll, kqueue o strutture simili che l'OS fornisce per l'I/O multiplexing.

Per altri tipi di chiamate di sistema di blocco che non possono essere multiplexate con qualcosa come epoll, Go genera un nuovo thread del sistema operativo, indipendentemente dall'impostazione di GOMAXPROCS (anche se era lo stato in Go 1.1, non sono sicuro se il la situazione è cambiata)

+0

Non vedo alcun motivo per un voto negativo. Questa risposta lo riassume molto bene. – nemo

+4

Questo perché 'GOMAXPROCS' non gestisce il numero di goroutine che possono essere in esecuzione. Almeno, non nel contesto della domanda. E il 'GOMAXPROCS' non impedisce di andare a creare più thread. Impedisce solo di eseguirli su più processori ... – Elwinar

+1

@Elwinar 'GOMAXPROCS' imposta il numero di thread di sistema che eseguono il codice Go simultaneamente. Poiché ogni codice go è associato a una goroutine, ciò limita efficacemente il numero di routine go in esecuzione simultanea. Inoltre, nos spiega piuttosto bene che ci può essere * più di un * thread di sistema, anche se 'GOMAXPROCS' è 1. Inoltre, i processori non hanno nulla a che fare con questo. – nemo

5

Bisogna differenziare numero processore e il numero del filo: si può avere più thread di processori fisici, quindi un processo multi-thread ancora possibile eseguire su un singolo microprocessore.

Come la documentazione citata spiega, una goroutine non è un thread: è semplicemente una funzione eseguita in un thread a cui è dedicato un blocco dello spazio di stack. Se il tuo processo ha più di un thread, questa funzione può essere eseguita da entrambi i thread. Quindi una goroutine che sta bloccando per un motivo o un altro (syscall, I/O, sincronizzazione) può essere lasciata nel suo thread mentre altre routine possono essere eseguite da un altro.

21

Ok, ecco cosa ho imparato: Quando si eseguono syscalls non elaborati, Go crea effettivamente un thread per blocco goroutine. Ad esempio, prendere in considerazione il seguente codice:

package main 

import (
     "fmt" 
     "syscall" 
) 

func block(c chan bool) { 
     fmt.Println("block() enter") 
     buf := make([]byte, 1024) 
     _, _ = syscall.Read(0, buf) // block on doing an unbuffered read on STDIN 
     fmt.Println("block() exit") 
     c <- true // main() we're done 
} 

func main() { 
     c := make(chan bool) 
     for i := 0; i < 1000; i++ { 
       go block(c) 
     } 
     for i := 0; i < 1000; i++ { 
       _ = <-c 
     } 
} 

Durante l'esecuzione, Ubuntu 12.04 ha segnalato 1004 thread per tale processo.

D'altra parte, quando si utilizza server HTTP Go e l'apertura 1000 prese ad esso, sono stati creati solo 4 fili del sistema operativo:

package main 

import (
     "fmt" 
     "net/http" 
) 

func handler(w http.ResponseWriter, r *http.Request) { 
     fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) 
} 

func main() { 
     http.HandleFunc("/", handler) 
     http.ListenAndServe(":8080", nil) 
} 

Quindi, è un mix tra un IOLoop e di un thread per ogni sistema di bloccaggio chiamata.

+0

utilizza epoll nativo (o alternativo su altri sistemi) per i socket, non lo usa per il file io, c'era una discussione su di esso da qualche parte sulla mailing list. – OneOfOne

+2

Il runtime di Go ha una funzione chiamata polling di rete https://golang.org/src/runtime/netpoll.go Utilizza API native non bloccanti disponibili sul SO di destinazione per gestire l'I/O della rete in modo da poter disporre di tutte le goroutine tutte usando la rete IO. – creker

+1

L'I/O non bloccante non è una novità. Node.js o Java NIO o molte altre lingue lo supportano sfruttando le chiamate fornite dal sistema operativo. – user1870400

Problemi correlati