Linux Golang,进程和共享内存

Linux Golang,进程和共享内存,linux,go,process,ipc,shared-memory,Linux,Go,Process,Ipc,Shared Memory,今天我的一个朋友告诉我,Go程序可以在多个CPU核上进行自我扩展。听说系统任务调度器对goroutine一无所知,因此无法在多个内核上运行它们,我感到非常惊讶 我做了一些搜索,发现Go程序可以生成多个操作系统任务,在不同的内核上运行它们。数量由GOMAXPROCS环境变量控制。但据我所知,分叉一个进程会导致进程数据的完整拷贝,不同的进程在不同的地址空间中运行 那么Go程序中的全局变量呢?与多个goroutine一起使用安全吗?它们是否以某种方式在系统进程之间同步?如果他们这样做了,怎么做?我主要

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

我做了一些搜索,发现Go程序可以生成多个操作系统任务,在不同的内核上运行它们。数量由GOMAXPROCS环境变量控制。但据我所知,分叉一个进程会导致进程数据的完整拷贝,不同的进程在不同的地址空间中运行


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

我明白了!一切都在进行中

有一个我不知道的Linux系统调用。 这叫克隆。它比叉子更灵活,并且允许 子进程将位于其父进程的地址空间中

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

首先,src/runtime/proc.go中有一个newm函数。这 函数负责创建新的工作线程 或注释中所称的机器

// 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
}
克隆功能在特定体系结构中定义 文件夹。对于amd64,它位于src/runtime/sys\u linux\u amd64.s中。 这是实际的系统调用

所以Go程序确实在多个OS线程中运行,这使得 跨越CPU,但它们使用一个共享地址空间


呸。。。我喜欢去。

我想到了!一切都在进行中

有一个我不知道的Linux系统调用。 这叫克隆。它比叉子更灵活,并且允许 子进程将位于其父进程的地址空间中

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

首先,src/runtime/proc.go中有一个newm函数。这 函数负责创建新的工作线程 或注释中所称的机器

// 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
}
克隆功能在特定体系结构中定义 文件夹。对于amd64,它位于src/runtime/sys\u linux\u amd64.s中。 这是实际的系统调用

所以Go程序确实在多个OS线程中运行,这使得 跨越CPU,但它们使用一个共享地址空间


呸。。。我喜欢Go。

应该会有帮助。还有。@chrk,问题是:官方文档和第二篇文章都没有阐明Go运行时如何提供共享变量的同步。官方文档声明:goroutine有一个简单的模型:它是一个与同一地址空间中的其他goroutine并发执行的函数。但是如果它们在不同的进程中,它们就不可能在同一个地址空间中……那么让我们再仔细阅读一遍。它说:它们被称为goroutine,因为现有的术语threads、corroutine、processs等等传达了不准确的含义;所以不要假设它们是过程。就地址空间而言,它指出goroutine被多路复用到多个操作系统线程上。我不打算在这里提供完整的答案,但为了自己找到问题的答案,您真正需要研究的是线程在Linux中的工作方式;然后测试:strace、/proc/*并在中查看一些答案,以便了解更高级的Stuff线程在linux中也称为轻量级进程。每个线程都可以位于一个单独的核心上,并且有自己的堆栈,但是共享生成进程的地址空间共享内存应该会有所帮助。还有@chrk,问题是:官方文档和第二篇文章都没有说明go runtime如何提供共享变量的同步。官方文档声明:goroutine有一个简单的模型:它是一个与同一地址空间中的其他goroutine并发执行的函数。但是如果它们在不同的进程中,它们就不可能在同一个地址空间中……那么让我们再仔细阅读一遍。它说:它们被称为goroutine,因为现有的术语threads、corroutine、processs等等传达了不准确的含义;所以不要假设它们是过程。就地址空间而言,它指出goroutine被多路复用到多个操作系统线程上。我不打算在这里提供完整的答案,但为了自己找到问题的答案,您真正需要研究的是线程在Linux中的工作方式;然后测试:strace、/proc/*并在中查看一些答案,以便了解更高级的Stuff线程在linux中也称为轻量级进程。每个线程可以位于一个单独的核心上,并有自己的堆栈,但共享 生成进程共享内存的地址空间