Golang、进程和共享内存

4
今天我的一个朋友告诉我,Go程序可以在多个CPU核上进行自我扩展。听到这个消息后,我感到非常惊讶,因为系统任务调度程序不知道任何有关goroutines的信息,因此无法在多个核上运行它们。
我进行了一些搜索,并发现Go程序可以生成多个OS任务以在不同的核上运行它们(该数量由GOMAXPROCS环境变量控制)。但据我所知,fork进程会导致完全复制进程数据,并且不同的进程运行在不同的地址空间中。
那么,在Go程序中的全局变量怎么办呢?它们在与多个goroutine一起使用时是安全的吗?它们是否会在系统进程之间进行同步?如果确实如此,那么它们是如何实现的呢?我主要关心的是Linux和FreeBSD的实现。

2
官方的goroutines文档应该会很有帮助。 - chrk
除了这篇文章 - chrk
2
让我们仔细再读一遍。它说:“它们被称为goroutines,因为现有的术语——线程、协程、进程等——传达了不准确的内涵”,所以不要认为它们是进程。就地址空间而言,它指出“Goroutines被多路复用到多个操作系统线程上”。我不打算在这里提供完整的答案,但你真正需要研究的是如何在Linux中使用线程;然后测试:strace/proc/<PID>/*,并在SO中查看更高级的内容以获取更多答案。 - chrk
@JimB,嗯,这个答案说Linux任务调度器一次只能在一个CPU核心上运行一个进程。这意味着Go程序必须使用多个OS任务来利用多个核心。这意味着每个任务都有不同的地址空间。我错了吗? - ea7ababe
1
在Linux中,线程也被称为轻量级进程(http://www.tldp.org/FAQ/Threads-FAQ/Types.html)。每个线程可以在单独的核心上运行,并拥有自己的堆栈,但共享生成进程的地址空间(共享内存)。 - David Budworth
显示剩余4条评论
1个回答

7

我明白了!所有的问题都在go源代码中。

有一个名为"clone"的Linux系统调用,我之前不知道它的存在。 它比fork更加灵活,允许子进程在父进程的地址空间中运行。

以下是线程创建过程的简要概述。

首先,在src/runtime/proc.go中有一个名为newm的函数。此函数负责创建新的工作线程(或者在注释中称之为“machine”)。

// Create a new m. It will start off with a call to fn, or else the scheduler.
// fn needs to be static and not a heap allocated closure.
// May run with m.p==nil, so write barriers are not allowed.
//go:nowritebarrier
func newm(fn func(), _p_ *p) {

    // ... some code skipped ...

    newosproc(mp, unsafe.Pointer(mp.g0.stack.hi))
}

这个函数调用了newosproc,它是特定于操作系统的。 对于Linux,可以在src/runtime/os_linux.go中找到它。以下是该文件的相关部分:

var (
    // ...

    cloneFlags = _CLONE_VM | /* share memory */
        _CLONE_FS | /* share cwd, etc */
        _CLONE_FILES | /* share fd table */
        _CLONE_SIGHAND | /* share sig handler table */
        _CLONE_THREAD /* revisit - okay for now */
)

// May run with m.p==nil, so write barriers are not allowed.
//go:nowritebarrier
func newosproc(mp *m, stk unsafe.Pointer) {

    // ... some code skipped ...

    ret := clone(cloneFlags, /* ... other flags ... */)

    // ... code skipped
}

clone函数的定义在特定于架构的文件中。对于amd64,它在src/runtime/sys_linux_amd64.s中。这是实际的系统调用。

因此,Go程序确实在多个操作系统线程中运行,从而实现跨CPU扩展,但它们使用一个共享的地址空间。

哇...我喜欢Go。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接