2016-12-25 4 views
0

Сегодня мой друг сказал мне, что программы Go могут масштабироваться на нескольких ядрах процессора. Я был очень удивлен, услышав, что, зная, что системные планировщики задач ничего не знают о goroutines и, следовательно, не могут запускать их на нескольких ядрах.Голанг, процессы и общая память

Я сделал поиск и выяснил, что программы Go могут запускать несколько задач ОС для их запуска на разных ядрах (число контролируется переменной среды GOMAXPROCS). Но, насколько я знаю, процесс форсинга приводит к полной копии данных процесса и различным процессам, выполняемым в разных адресных пространствах.

А как насчет глобальных переменных в программах Go? Безопасны ли они для использования с несколькими goroutines? Как-то они синхронизируются между системными процессами? И если они это сделают, то как? Я в основном обеспокоен реализацией linux и freebsd.

+2

[Официальная документация на goroutines] (https://golang.org/doc/effective_go.html#goroutines) должна быть полезна. – chrk

+0

Как и [эта статья] (https://www.goinggo.net/2014/01/concurrency-goroutines-and-gomaxprocs.html). – chrk

+0

@chrk, проблема в том, что официальная документация или вторая статья не проливают свет на то, как запустить runtime обеспечивает синхронизацию общих переменных. В официальной документации говорится: «Горотин имеет простую модель: это функция, выполняемая одновременно с другими goroutines в одном и том же адресном пространстве». Но они не могут находиться в одном и том же адресном пространстве, если они находятся в разных процессах ... – ea7ababe

ответ

4

Я понял! Это все в источниках.

Существует системный вызов Linux, о котором я не знал. Это называется «клон». Он более гибкий, чем fork, и позволяет дочернему процессу жить в адресном пространстве своего родителя.

Вот краткий обзор процесса создания потоков.

Первая функция newm в src/runtime/proc.go. Эта функция отвечает за создание нового рабочего потока (или машина, как она называется в комментариях).

// 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. Это фактический системный вызов.

Таким образом, программы Go Go запускаются в нескольких потоках ОС, что позволяет охватывать процессоры, но они используют одно общее адресное пространство.

Фу ... Я люблю идти.

Смежные вопросы