Go 线程相关(非协程)

前奏

在用户层面,只能接触到Go语言的协程,也就是goroutine。对于线程的存在是感知不到的。

Go 语言使用M:N的线程模型,将M个goroutine绑定到N个操作系统线程上执行,N为runtime.GOMAXPROCS(0),即可执行的最大CPU数。所以假设有4个逻辑核心,那么就将M个goroutine调度到4个操作系统线程上。但是Go程序所能使用到的线程个数远不止于此,由系统调用产生的线程,及I/O阻塞的线程总数应低于10000,也就是默认线程数不会超过10000。

但是可以使用debug.SetMaxThreads(10001)重置最大线程数。

Go语言的线程目前只会膨胀增长,不会被自动销毁
手动销毁Go线程的解决方案在Go官方 issues#14592: "runtime: let idle OS threads exit"中提到过。即使用runtime.LockOSThread()runtime.UnlockOSThread()

src/runtime/proc.go
LockOSThread wires the calling goroutine to its current operating system thread.The calling goroutine will always execute in that thread,and no other goroutine will execute in it,until the calling goroutine has made as many calls to UnlockOSThread as to LockOSThread.If the calling goroutine exits without unlocking the thread,the thread will be terminated.
All init functions are run on the startup thread. Calling LockOSThread from an init function will cause the main function to be invoked on that thread.
A goroutine should call LockOSThread before calling OS services or non-Go library functions that depend on per-thread state.

LockOSThread将调用goroutine连接到其当前操作系统线程。调用 goroutine 将始终在该线程中执行,并且不会在其中执行其他 goroutine,直到调用 goroutine 对 UnlockOSThread 的调用与对 LockOSThread 的调用次数一样多。如果调用 goroutine 退出而不解锁线程,线程将被终止。所有 init 函数都在启动线程上运行。从 init 函数调用 LockOSThread 将导致在该线程上调用主函数。go例程应该在调用操作系统服务或依赖于每个线程状态的非 Go 库函数之前调用 LockOSThread。

UnlockOSThread undoes an earlier call to LockOSThread.If this drops the number of active LockOSThread calls on the calling goroutine to zero, it unwires the calling goroutine from its fixed operating system thread.
If there are no active LockOSThread calls, this is a no-op. Before calling UnlockOSThread, the caller must ensure that the OS thread is suitable for running other goroutines. If the caller made any permanent changes to the state of the thread that would affect other goroutines, it should not call this function and thus leave the goroutine locked to the OS thread until the goroutine (and hence the thread) exits.

UnlockOSThread撤消了之前对LockOSThread的调用。如果这会将调用 goroutine 上的活动 LockOSThread 调用数降至零,则会从其固定的操作系统线程中取消连接调用 goroutine。如果没有活动的 LockOSThread 调用,则为无操作。在调用 UnlockOSThread 之前,调用方必须确保操作系统线程适合运行其他 goroutine。如果调用方对线程的状态进行了任何会影响其他 goroutines 的永久更改,则它不应调用此函数,从而将 goroutine 锁定到操作系统线程,直到 goroutine(以及线程)退出。

相关代码

GoMAXPROCS() 设置可执行的最大CPU数,并返回上一次设置的数量。

	fmt.Println(runtime.GOMAXPROCS(3)) // 4
	fmt.Println(runtime.GOMAXPROCS(0)) // 3

其位于src/runtime/debug.go

// GOMAXPROCS sets the maximum number of CPUs that can be executing
// simultaneously and returns the previous setting. It defaults to
// the value of runtime.NumCPU. If n < 1, it does not change the current setting.
// This call will go away when the scheduler improves.
// GOMAXPROCS设置可执行的最大CPU数并返回先前的设置。默认为
// runtime.NumCPU的值。如果n<1,则不会更改当前设置。
// 当调度程序改进时,此调用将消失。
func GOMAXPROCS(n int) int {
	if GOARCH == "wasm" && n > 1 {
		n = 1 // WebAssembly has no threads yet, so only one CPU is possible.
	}

	lock(&sched.lock)
	ret := int(gomaxprocs) // 默认为内置的gomaxprocs数量
	unlock(&sched.lock)
	if n <= 0 || n == ret {
		return ret
	}

	stopTheWorldGC("GOMAXPROCS") // STW

	// newprocs will be processed by startTheWorld
	newprocs = int32(n)

	startTheWorldGC()
	return ret
}

Reference
https://www.waimaiguai.com/technology/article/1881554
https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html
https://github.com/golang/go/issues/4056
https://github.com/golang/go/issues/14592

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

metabit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值