Go 并发

Go 并发

golang 语言如何实现并发?
用 sync.WaitGroup,chan,goroutine,context

  • 并发:用一个逻辑处理器控制,简单说就是一个线程可以处理多个函数,在这里,用协程,go func ,就是 goroutine ,用户态级别,切换上下文消耗时间和资源都很小,从而实现高并发,一段时间可以处理多个函数
  • 并行:就是这段时间,这个线程就只能处理一个函数,但是多来几个线程就能多处理一些函数了

控制线程个数的代码叫做——GOMAXPROCS(2),而用来控制同步的叫做信号量计数器,用 sync.WaitGroup 控制,wg.Add(2),控制的几个协程实现同步,如果这两个参数都设置为2,那么就是并行了,两个线程对应两个协程,刚好,但是如果把GOMAXPROCS设置为1,就是并发了

关于并发,有两种情况

1、就非共享性的,执行函数的就直接用 GMP调度的方式就行

2、对于需要访问共享性资源的,可以用 automic\mutex\chan\context 避免竞争状态和保证数据的一致性安全性

先简单说一下第一种情况

  • 可以想想出来一个图,上边是 M 线程,中间是 P 逻辑处理器,下边是协程 goroutine ,P 维护着一个 G 的队列,由 P 逻辑处理器去控制 goroutine 的执行时间和顺序,这可能会出现一些情况,例如,当前 P 控制 G1 协程运行,但是运行时间太长,或者 G1 本身出现了问题,那么 P 就会决定带着 G 队列出来,再去开一个 M2 线程,执行下一个 G ,当然了,原先的 M1 和 G阻塞的继续他们的
  • 另外稍微正常一点的就是,G1 运行时间长,但是没有阻塞,这时候 P 会决定让当前G1回到G队列的队尾去执行下一个G

对于需要访问共享性资源的并发,先不说autmic方式,说一下加锁 sync.mutex.lock 的实现

  • 在起来一个程序前,我们先 var wg waitGroup 声明一下,再 wg.Add(2),表示执行两个 goroutin ,信号量计数,初始化一个 mutex 对象,接着起来 goroutine1和goroutine2,举个例子,对于一个变量 int a = 1,G1,先读取到 a = 1,G2 读取到 a = 1,G1对a++ ,G2对a++,这时候 a = ?,答案是 1 ,因为G2它读取到的 a = 1,这就是说,明明++了两次,但是结果确实 2 ,和我们想要的不一样,这时候可以加锁,具体实现是下边
  • 它的实现原理其实就是,就算G1退出了,但是因为被锁住了,所以接下来还是进入这个G1,直到锁释放才能切换到另一个协程操作这个共享资源
var wg sync.WaitGroup
var mutex sync.Mutex
var counter int

func main() {
	wg.Add(2)
	go incCounter(1)
	go incCounter(2)
	wg.Wait()
}
func incCounter(id int) {
	defer wg.Done()
	for count := 0; count < 4; count++ {
    mutex.Lock(){
      value := counter
      fmt.Printf("id: %v 打印: %v\n", id, counter)
      runtime.Gosched()
      value++
      counter = value
      fmt.Printf("id: %v 打印: %v\n", id, counter)
    }
    mutex.Unlock()
	}
}

你可能感兴趣的:(golang)