GO语言goroutine

Posted 两片空白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GO语言goroutine相关的知识,希望对你有一定的参考价值。

前言

        go语言对于并发编程有原生的支持。

        如下代码:创建10个协程并发执行。

package main

import (
	"fmt"
	"time"
)

func main() 
	for i := 0; i < 10; i++ 
		go func(i int) 
			fmt.Printf("hello from goroutine %d\\n", i)
		(i)
	
	//main函数执行完,协程也会被终止,等待1秒,协程执行完
	time.Sleep(time.Second)

Courotine 协程:

1. go语言中开辟的实际是协程,协程是轻量级线程。作用和线程差不多,并发执行任务。

        在go语言中可以开辟很多协程,比如:1000个协程,但是开辟1000个线程消耗的资源就比较多了。

2. 协程为什么是轻量级线程。

        go语言中的协程是非抢占式多任务处理,由协程主动交出控制权。

        抢占式式多任务处理:操作系统由更高优先级的任务,可以停止当前执行的线程,去执行更高优先级线程。

        非抢占式多任务处理:操作系统不能主动去停止。而是由任务主动交出控制权。

        线程是抢占式多任务处理,所以等任务切换时,需要内存来保存程序执行的上下文。

        协程不需要那麽多内存来保存上下文,只需要保存切换点。

        协程是编译器/解释器/虚拟机层面的多任务,不是操作系统层面的多任务。操作系统层面没有协程,

        所以协程是轻量级线程。

3. 多个协程可能在一个或者多个线程上执行。

        我们知道操作系统有调度器,而go语言也有自己的调度器,来调度协程的运行。所以可能协程在不同的一个或者一个线程上运行。

参数传递给协程的注意点:

代码:

        每次开辟的协程参数i需要被传入,如果不传入,会出现越界错误。

        因为使用的i在全局只有一份,当i被加到10时,有的协程还没有运行完或者正在运行,此时i时同一个,再执行a[i]时,就越界了,作为参数传入,i会被拷贝一份,每个协程私有。

package main

import (
	"fmt"
	"time"
)

func main() 
	var a [10]int
	for i := 0; i < 10; i++ 
		go func(i int) 
			for 
				a[i]++
			
		(i)
        // 会吹按越界错误
		// go func() 
		// 	for 
		// 		a[i]++
		// 	
		// ()
	
	//main函数执行完,协程也会被终止,等待1秒,协程执行完
	time.Sleep(time.Second)
	fmt.Println(a)

可以在命令行中可以输入go run -race xxx, 查看访问冲突。

 

go语言的调度器

        子程序(普通函数)是协程的特例。

  1.  任何函数前加上go关键字,就能送给调度器调度,
  2.  虽然协程是非抢占式的,但是为了提高效率,调度器会在合适的点进行切换,不需要显示去切换。

一般的切换点:并不保存会切换,也不能保证在别的地方不切换。

  • I/O操作,Select
  • channel
  • 等待锁
  • 函数调用(有时)
  • runtime.Gosched(),显示切换

go语言的协程可能运行在一个线程里,也可能多个协程运行在一个线程里,也有可能多个协程在多个线程里,这由go语言调度器来决定。

 

以上是关于GO语言goroutine的主要内容,如果未能解决你的问题,请参考以下文章

Go语言8-goroutine和channel

Go语言基础之并发

golang语言并发与并行——goroutine和channel的详细理解

goroutine/Gosched/Goexit/GOMAXPROCS

Go part 8 并发编程

go14--并发concurrency,Goroutine ,channel