Jak działają goroutines? (lub: goroutines i OS threads relation)

W Jaki Sposób inne goroutines mogą nadal wykonywać podczas wywoływania syscall? (przy użyciu GOMAXPROCS=1)
O ile mi wiadomo, podczas wywoływania syscall wątek traci kontrolę, dopóki syscall nie powróci. Jak Go osiągnąć tę współbieżność bez tworzenia wątku systemowego na blocking-on - syscall goroutine?

Z dokumentacji:

Goroutines

Nazywają się goroutines, ponieważ istniejące terminy-threads, koroutiny, procesy i tak on-przekazać niedokładne konotacje. A goroutine ma prosty model: jest to funkcja wykonująca jednocześnie z innymi goroutinami w tej samej przestrzeni adresowej. Jest lekki, kosztuje niewiele więcej niż alokacja przestrzeni stosu. I stosy zacząć od małych, więc są tanie i rosną poprzez przydzielanie (i uwalnianie) przechowywanie sterty w razie potrzeby.

Goroutiny są multipleksowane na wiele wątków OS więc jeśli ktoś powinien blokuj, np. czekając na wejście / wyjście, inne nadal działają. Ich design skrywa wiele złożoności tworzenia wątków i zarządzanie.

Author: omribahumi, 2014-07-06

4 answers

Jeśli goroutine blokuje, runtime uruchomi nowy wątek OS, aby obsłużyć inne goroutine, dopóki blokujący nie przestanie blokować.

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

 27
Author: OneOfOne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-06 19:57:58

Ok, więc oto czego się nauczyłem: Kiedy robisz surowe syscalls, go indeed tworzy wątek na blokowanie goroutine. Na przykład rozważ następujący kod:

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
        }
}
Ubuntu 12.04 zgłosiło 1004 wątków dla tego procesu.

Z drugiej strony, podczas korzystania z serwera HTTP Go i otwierania 1000 gniazd do niego, utworzono tylko 4 wątki systemu operacyjnego:

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)
}
Więc jest to mieszanka IOLoop i wątku na blokujące wywołanie systemowe.
 23
Author: omribahumi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-06 21:23:31

Nie może. jest tylko 1 goroutine, który może być uruchomiony w czasie, gdy GOMAXPROCS=1, Czy ten goroutine wykonuje wywołanie systemowe, czy coś innego.

Jednak większość blokujących wywołań systemowych, takich jak gniazda I/O, czekających na timer, nie jest blokowana w wywołaniu systemowym, gdy jest wykonywana z Go. Są one multipleksowane przez runtime Go na epoll, kqueue lub podobne udogodnienia, które System operacyjny zapewnia do multipleksowania I / o.

Dla innych rodzajów blokowania wywołań systemowych, które nie mogą być w przypadku Go 1.1 nie jest to jednak możliwe, ponieważ w przypadku Go 1.1 nie jest to możliwe, ponieważ nie jest to możliwe, ponieważ nie jest to możliwe, ponieważ w przypadku Go 1.1 nie jest to możliwe.]}

 12
Author: nos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-03 12:26:57

Musisz odróżnić numer procesora OD NUMERU wątku: możesz mieć więcej wątków niż fizyczne procesory, więc proces wielowątkowy może nadal wykonywać na pojedynczym procesorze.

Jak wyjaśnia przytoczona dokumentacja, goroutine nie jest wątkiem: jest tylko funkcją wykonywaną w wątku, który jest poświęcony kawałkowi przestrzeni stosu. Jeśli twój proces ma więcej niż jeden wątek, ta funkcja może być wykonywana przez każdy wątek. Więc goroutine, który blokuje z jakiegoś powodu lub inny (syscall, I/O, synchronizacja) może być wpuszczony do jego wątku, podczas gdy inne procedury mogą być wykonywane przez inny.

 5
Author: Elwinar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-06 20:00:53