78 votes

Comment fonctionnent les goroutines? (ou: relation goroutines et threads OS)

Comment peut-autres goroutines garder de l'exécution, tout en invoquant un syscall? (lors de l'utilisation de GOMAXPROCS=1)
Pour autant que je suis au courant de, lors de l'invocation d'un syscall le fil donne le contrôle jusqu'à ce que le syscall retourne. Comment Allez atteindre cette simultanéité sans la création d'un système de thread par blocage-sur-syscall goroutine?

À partir de la documentation:

Goroutines

Ils sont appelés les goroutines parce que les conditions existantes-fils, coroutines, de processus, et ainsi de suite-transmettre inexactes connotations. Un goroutine a un modèle simple: c'est une fonction qui s'exécute simultanément avec d'autres goroutines dans le même espace d'adressage. Il est léger, coûts peu plus que l'allocation de l'espace de pile. Et les piles commencez petit, de sorte qu'ils sont bon marché, et de grandir en allouant (et libérer) tas de stockage que nécessaire.

Goroutines sont multiplexées sur plusieurs OS threads donc, si l'on doit bloc, comme lors de l'attente pour les e/S, d'autres continuent à s'exécuter. Leur le design se cache de nombreuses complexités de la création de thread et de la gestion.

52voto

OneOfOne Points 15558

Si un goroutine bloque, le runtime démarrera un nouveau thread OS pour gérer les autres goroutines jusqu'à ce que le blocage arrête de bloquer.

Référence: https://groups.google.com/forum/#!topic/golang-nuts/2IdA34yR8gQ

35voto

omribahumi Points 468

Ok, donc voici ce que j'ai appris: Lorsque vous êtes en train de faire raw syscalls, Allez en effet crée un thread par le blocage goroutine. Par exemple, considérons le code suivant:

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
        }
}

Lors de l'exécution, Ubuntu 12.04 signalé 1004 threads pour ce processus.

D'autre part, lors de l'utilisation de Go serveur HTTP et l'ouverture de 1000 sockets, seulement 4 threads du système d'exploitation ont été créés:

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)
}

Donc, c'est un mélange entre un IOLoop et un thread par le système de blocage d'appel.

22voto

nos Points 102226

Il ne peut pas. Il y a seulement 1 go de routine qui peuvent être en cours d'exécution à un moment où GOMAXPROCS=1, si un coup de routine est de faire un appel système ou quelque chose d'autre.

Cependant, la plupart des système de blocage des appels, telles que la prise I/O, en attente d'une minuterie ne sont pas bloqués sur un système d'appel lorsqu'elle est effectuée à partir d'y aller. Ils sont multiplexés par go d'exécution sur epoll, kqueue ou d'autres établissements de l'OS pour le multiplexage I/O.

Pour d'autres types de système de blocage des appels qui ne peuvent être multiplexées avec quelque chose comme epoll, allez ne se frayer un nouveau système d'exploitation fil, quel que soit le GOMAXPROCS paramètre (quoique c'était l'état en aller 1.1, je ne sais pas si la situation est modifiée)

6voto

Elwinar Points 2029

Vous devez vous différencier numéro du processeur et le nombre de thread: vous pouvez avoir plus de threads que de processeurs physiques, de sorte qu'un processus multi-thread peut encore s'exécuter sur un processeur mono-coeur.

La documentation que vous avez cité expliquer, une goroutine n'est pas un fil: il s'agit simplement d'une fonction exécutée dans un thread dédié un morceau d'espace de pile. Si votre processus ont plus qu'à un fil, cette fonction peut être exécutée par le thread. Ainsi, une goroutine qui bloque pour une raison ou une autre (syscall, I/O, la synchronisation) peut être laissé dans son thread alors que d'autres routines peut être exécuté par un autre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X