How do goroutines work? (or: goroutines and OS threads relation)

坚强是说给别人听的谎言 提交于 2019-11-28 15:38:51

If a goroutine is blocking, the runtime will start a new OS thread to handle the other goroutines until the blocking one stops blocking.

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

Ok, so here's what I've learned: When you're doing raw syscalls, Go indeed creates a thread per blocking goroutine. For example, consider the following code:

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

When running it, Ubuntu 12.04 reported 1004 threads for that process.

On the other hand, when utilizing Go's HTTP server and opening 1000 sockets to it, only 4 operating system threads were created:

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

So, it's a mix between an IOLoop and a thread per blocking system call.

It can't. There's only 1 goroutine that can be running at a time when GOMAXPROCS=1, whether that one goroutine is doing a system call or something else.

However, most blocking system calls, such as socket I/O, waiting for a timer are not blocked on a system call when performed from Go. They're multiplexed by the Go runtime onto epoll, kqueue or similar facilities the OS provides for multiplexing I/O.

For other kinds of blocking system calls that cannot be multiplexed with something like epoll, Go does spawn a new OS thread, regardless of the GOMAXPROCS setting (albeit that was the state in Go 1.1, I'm not sure if the situation is changed)

You have to differentiate processor number and thread number: you can have more threads than physical processors, so a multi-thread process can still execute on a single core processor.

As the documentation you quoted explain, a goroutine isn't a thread: it's merely a function executed in a thread that is dedicated a chunk of stack space. If your process have more than one thread, this function can be executed by either thread. So a goroutine that is blocking for a reason or another (syscall, I/O, synchronization) can be let in its thread while other routines can be executed by another.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!