Go语言并发组件

Go中的并发组件

1、Goroutine

Goroutine: go语言程序中最基本的组织单位之一,每个Go程序中至少会有一个main goroutine,在进程开始时自动创建并启动。是一个并发函数,在程序中使用go关键字进行触发
gorountine如何工作?
A、goroutine与Go语言在运行时是深度集成的
B、goroutine没有定义自己的暂停方法或再运行点
C、Go语言再运行时会观察goroutine的运行时行为,再它们阻塞时自动挂起,不阻塞时恢复,使得goroutione在阻塞时成为可抢占的
D、协程和goroutione是隐式并发结构,但并发不是二者的属性

它们是OS线程或绿色线程吗?
Goroutine不是,是更高级别的抽象协程

绿色线程:相对于操作系统线程,操作系统线程是指程序中会真正的映射到操作系统的线程,绿色线程是指程序中不会映射到操作系统中有语言映射平台自身来调度(由语言运行时管理的线程)
协程:非抢占式的简单并发子goroutine(函数, 闭包或方法), 不能被中断,协程由多个点允许暂停或重新进入

Go语言的主机托管机制:M:N调度器
M个绿色线程映射到N个OS线程,goroutine数量如果大于绿色线程时,这时调度程序会处理分布在可用线程上的goroutine,保证正常运行
Go语言的并发模型fork-join模型:
fork-join并发模型
fork:指在程序的任意一点,可以将执行的子分支与其父节点同时运行
join:将来某个时间,这些并发的执行分支将会合并在一起

Goroutine与GC:
用于计算创建一个goroutine消耗的内存

memConsumed := func ()uint64{
		runtime.GC()
		var s runtime.MemStats
		runtime.ReadMemStats(&s)
		return s.Sys
	}
	var c <-chan interface{}
	var wg sync.WaitGroup
	noop := func(){ wg.Done(); <-c}
	const numGoroutines = 1e4
	wg.Add(numGoroutines)
	before := memConsumed()
	for i := numGoroutines; i > 0; i--{
		go noop()
	}
	wg.Wait()
	after := memConsumed()
	fmt.Printf("%.3fkb", float64(after - before)/numGoroutines/1000)

理论上8GB内存的计算机在不交换空间的情况下可以启动百万量级的goroutine,可能会影响性能的是上下文,因为OS线程的开销是相当大的,相比之下软件的上下文切换就会廉价
OS线程切换上下文:os线程必须保存如:寄存器,查找表和内存映射之类的东西,以便在有限的时间内成功地切换回当前线程
对比OS线程和goroutine之间切换上下文时的相对性能对比:

Linux基准测试
taskset -c 0 perf bench sched pipe -T
结果:
# Running 'sched/pipe' benchmark:
# Executed 1000000 pipe operations between two threads

     Total time: 2.276 [sec]

       2.276609 usecs/op
         439249 ops/sec

go中的测试
func BenchmarkContestSwitch(b *testing.B){
	var wg sync.WaitGroup
	begin := make(chan struct{})
	c := make(chan struct{})
	var token struct{}
	sender := func(){
		defer wg.Done()
		<- begin
		for i := 0; i < b.N; i++{
			c <- token
		}
	}
	receiver := func(){
		defer wg.Done()
		<-begin
		for i := 0; i < b.N; i++{
			<-c
		}
	}
	wg.Add(2)
	go sender()
	go receiver()
	b.StartTimer()
	close(begin)
	wg.Wait()
}
结果
go test -bench=. -cpu=1  goroutine_test.go
goos: linux
goarch: amd64
BenchmarkContestSwitch 	10000000	       144 ns/op
PASS
ok  	command-line-arguments	1.597s

高效机制背后的秘密
1、goroutine既不是os线程。也不是应用层线程。
2、golang的M:N调度器。
3、golang的轻:一个新创建的goroutine赋予了几千字节,不运行,go会自动缩减内存。
4、goroutine的fork-join模型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值