当在golang中写入文件时阻塞了许多goroutine时,为什么不创建多个线程?

fra*_*lin 9 concurrency multithreading go goroutine

正如我们在go中所知,当goroutine必须执行阻塞调用(例如系统调用)或通过cgo调用C库时,可能会创建一个线程.一些测试代码:

   package main

   import (
        "io/ioutil"
        "os"
        "runtime"
        "strconv"
    )

    func main() {
        runtime.GOMAXPROCS(2)
        data, err := ioutil.ReadFile("./55555.log")
        if err != nil {
            println(err)
            return
        }
        for i := 0; i < 200; i++ {
            go func(n int) {
                for {
                    err := ioutil.WriteFile("testxxx"+strconv.Itoa(n), []byte(data), os.ModePerm)
                    if err != nil {
                        println(err)
                        break
                    }
                }
            }(i)
        }
        select {}
    }
Run Code Online (Sandbox Code Playgroud)

当我运行它时,它没有创建很多线程.

? =99=[root /root]$ cat /proc/9616/status | grep -i thread
Threads:    5
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Nic*_*ood 7

我稍微修改了你的程序以输出更大的块

package main

import (
    "io/ioutil"
    "os"
    "runtime"
    "strconv"
)

func main() {
    runtime.GOMAXPROCS(2)
    data := make([]byte, 128*1024*1024)
    for i := 0; i < 200; i++ {
        go func(n int) {
            for {
                err := ioutil.WriteFile("testxxx"+strconv.Itoa(n), []byte(data), os.ModePerm)
                if err != nil {
                    println(err)
                    break
                }
            }
        }(i)
    }
    select {}
}
Run Code Online (Sandbox Code Playgroud)

然后按预期显示> 200个线程

$ cat /proc/17033/status | grep -i thread
Threads:    203
Run Code Online (Sandbox Code Playgroud)

所以我认为系统调用在原始测试中退出太快,以显示您期望的效果.


icz*_*cza 5

goroutine是轻量级线程,它不等同于操作系统线程。的语言规范指定它作为一个“相同的地址空间内的控制的独立并发线程”

引用软件包的文档runtime

GOMAXPROCS变量限制了可以同时执行用户级Go代码的操作系统线程的数量。对于代表Go代码的系统调用中可以阻止的线程数量没有限制;那些不计入GOMAXPROCS限制。

仅仅因为您启动了200个goroutine,并不意味着将为它们启动200个线程。您将GOMAXPROCS其设置为2,这意味着可以同时运行2个“活动” goroutine。如果goroutine被阻塞(例如I / O等待),则可能会禁止新线程。您没有提到测试文件有多大,您启动的goroutine可能会太快地完成写入过程。

有效围棋博客文章将它们定义为:

之所以称它们为goroutine,是因为现有术语(线程,协程,进程等)传达了不准确的含义。goroutine有一个简单的模型:它是在同一地址空间中与其他goroutine同时执行的函数。它是轻量级的,仅比分配堆栈空间花费更多。而且堆栈从小开始,因此价格便宜,并且可以通过根据需要分配(和释放)堆存储来增长。

Goroutine被多路复用到多个OS线程上,因此,如果一个应阻塞,例如在等待I / O时,其他将继续运行。他们的设计隐藏了线程创建和管理的许多复杂性。

  • 语句“并且由于您明确地将 GOMAXPROCS 设置为 2,您不能指望它产生 200 个线程。”是不正确的。每个阻塞系统调用都可以创建一个新线程。 (3认同)