2016-12-25 211 views
0

今天我的一位朋友告訴我Go程序可以在多個CPU內核上擴展自己。聽到系統任務調度程序不知道goroutine的任何信息,並因此無法在多個內核上運行它們,我感到非常驚訝。Golang,進程和共享內存

我做了一些搜索和發現,圍棋程序可以生成多個操作系統的任務在不同內核上運行他們(數量由GOMAXPROCS環境變量控制)。但據我所知,分叉流程會導致完整的流程數據副本,而不同的流程會在不同的地址空間中運行。

那麼Go程序中的全局變量呢?他們可以安全地使用多個goroutines嗎?他們以某種方式在系統進程之間進行同步?如果他們這樣做,那麼如何?我主要關心linux和freebsd的實現。

+2

[夠程的官方文檔(https://golang.org/doc/effective_go.html#goroutines)應該是有幫助的。 – chrk

+0

以及[本文](https://www.goinggo.net/2014/01/concurrency-goroutines-and-gomaxprocs.html)。 – chrk

+0

@chrk,問題是:不是官方文檔,也不是第二篇文章闡明瞭如何去運行時提供共享變量的同步。官方文檔指出:「一個goroutine有一個簡單的模型:它是一個在同一地址空間中與其他goroutines同時執行的函數」。但是,如果他們處於不同的進程中,他們不能處於相同的地址空間中...... – ea7ababe

回答

4

我想通了!這一切都在源頭上。

有一個我不知道的Linux系統調用。 它被稱爲「克隆」。它比fork更靈活,它允許子進程在其父地址空間中生存。

下面是線程創建過程的簡要概述。

首先出現的是在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這是OS特定的。 對於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。 這是實際的系統調用。

所以走程序並在多個OS線程使 在CPU運行的跨越,但他們使用一個共享的地址空間。

P ...我喜歡Go。