今天,我的一个朋友告诉我,Go程序可以在多个CPU内核上进行扩展。听到系统任务调度程序对goroutine一无所知,因此无法在多个内核上运行它们,我感到非常惊讶。
我进行了一些搜索,发现Go程序可以产生多个OS任务以在不同的内核上运行它们(该数目由GOMAXPROCS环境变量控制)。但是据我所知,对流程进行分叉可导致流程数据的完整复制,并且不同的流程在不同的地址空间中运行。
那么Go程序中的全局变量呢?它们可以安全地与多个goroutine一起使用吗?它们是否以某种方式在系统进程之间同步?如果他们这样做,那又如何?我主要关注linux和freebsd的实现。
我想到了!全部使用源代码。
我没有意识到有一个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程序确实可以在多个OS线程中运行,从而可以跨越多个CPU,但是它们使用一个共享的地址空间。
ew ...我爱围棋。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句