Golang,进程和共享内存

时间:2016-12-25 15:28:01

标签: linux go process ipc shared-memory

今天我的一位朋友告诉我,Go程序可以在多个CPU核心上扩展自己。听到知道系统任务调度程序对goroutine一无所知并因此无法在多个内核上运行它时,我感到非常惊讶。

我做了一些搜索,发现Go程序可以产生多个OS任务,以便在不同的核心上运行它们(数量由GOMAXPROCS环境变量控制)。但据我所知,分支流程会导致流程数据的完整副本,并且不同的流程会在不同的地址空间中运行。

那么Go程序中的全局变量呢?它们与多种goroutine一起使用是否安全?他们以某种方式在系统进程之间同步吗?如果他们这样做了怎么样?我主要关注linux和freebsd的实现。

1 个答案:

答案 0 :(得分:4)

我明白了!一切都在消息来源。

有一个我不知道的Linux系统调用。 它被称为“克隆”。它比fork更灵活,它允许 一个子进程住在其父地址空间中。

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

首先newm中有一个src/runtime/proc.go函数。这个 function负责创建一个新的工作线程 (或在评论中调用的机器)。

// 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程序确实在多个OS线程中运行 跨越CPU,但它们使用一个共享地址空间。

Phew ......我喜欢Go。