Golang goroutine

协程Coroutine

  • 轻量级“线程”
  • 非抢占式多任务处理,由协程主动交出控制权
  • 编译器/解释器/虚拟机层面的多任务
  • 多个协程可以在一个或多个线程上运行
func main() {
	var a [10]int
	for i := 0; i < 10; i++ {
		go func(i int) {
			for {
				a[i]++
			}
		}(i)
	}
	time.Sleep(time.Microsecond)
	fmt.Println(a)
}

此代码会陷入到一个死循环中,因为goroutine没有主动交出控制权,此时使用查看任务管理器会发现任务所占CPU
发现任务基本占满了CPU,这时候需要手动交出控制权

func main() {
	var a [10]int
	for i := 0; i < 10; i++ {
		go func(i int) {
			for {
				a[i]++
				// 交出控制权,不主动传出控制权会陷入死循环,这就是非抢占
				runtime.Gosched()
			}
		}(i)
	}
	time.Sleep(time.Microsecond)
	fmt.Println(a)
}

这时候程序不会再进入死循环而使得其他goroutine无法运行

还有一个问题,如果我们不定义i int的话

func main() {
	var a [10]int
	for i := 0; i < 10; i++ {
		go func() {
			for {
				a[i]++
				// 交出控制权,不主动传出控制权会陷入死循环,这就是非抢占
				runtime.Gosched()
			}
		}()
	}
	time.Sleep(time.Microsecond)
	fmt.Println(a)
}

这个时候会出现这样一个错误

panic: runtime error: index out of range

这时候可以使用go的一些命令行参数来进行查看问题

go run -race goroutine.go

会获取这样的输出

WARNING: DATA RACE
Read at 0x00c00000a0b0 by goroutine 6:
  main.main.func1()
      D:/1important/Go/GoPath/src/Godemo/W1/day3/goroutine/goroutine.go:14 +0x77

Previous write at 0x00c00000a0b0 by main goroutine:
  main.main()
      D:/1important/Go/GoPath/src/Godemo/W1/day3/goroutine/goroutine.go:11 +0x122

Goroutine 6 (running) created at:
  main.main()
      D:/1important/Go/GoPath/src/Godemo/W1/day3/goroutine/goroutine.go:12 +0xf8

意思是说,在goroutine 6中,这个参数被读取了,但是之前在main goroutine中这个参数被写了,这样造成的溢出错误。再看上边的代码的时候,会发现由于函数式编程的概念a[i]++中的i和for循环中的i是同一个i,这样会造成i循环到10的时候虽然跳出了循环,但是在某个goroutine中i还是在被使用,这个时候的i是10,所以会产生数组溢出问题。
如果仔细观察会发现,在执行了go run -race goroutine.go后还有一个数据问题

Read at 0x00c000018190 by main goroutine:
  main.main()
      D:/1important/Go/GoPath/src/Godemo/W1/day3/goroutine/goroutine.go:21 +0x102

Previous write at 0x00c000018190 by goroutine 6:
  main.main.func1()
      D:/1important/Go/GoPath/src/Godemo/W1/day3/goroutine/goroutine.go:14 +0x6f

Goroutine 6 (running) created at:
  main.main()
      D:/1important/Go/GoPath/src/Godemo/W1/day3/goroutine/goroutine.go:12 +0xca

这个因为在使用fmt.Println(a)输出该数组的时候,还有某些goroutine在对数组a进行写入,这里需要使用channel来解决。

goroutine可能的切换点

  • I/O,select
  • channel
  • 等待锁
  • 函数调用(有时)
  • runtime.Gosched()
  • 只是参考,不能保证切换,不能保证其他地方不切换
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值