golang并发| 青训营笔记

73 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天.

基于CSP的并发特性

CSP

CSP(顺序通信进程)。在CSP中,程序是一组中间没有共享状态的平行运行的处理过程,它们之间使用管道进行通信和控制同步。

线程和协程

线程 :内核态,线程跑多个协程,栈MB级别。

协程 :用户态,轻量级线程,栈KB级别

Goroutines

每一个并发的执行单元叫作一个goroutine。 可以简单地把goroutine类比作一个线程。

当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine。新的goroutine会用go语句来创建。在语法上,go语句是一个普通的函数或方法调用前加上关键字go。go语句会使其语句中的函数在一个新创建的goroutine中运行。而go语句本身会迅速地完成。

channel

一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息。每个channel都有一个特殊的类型,也就是channels可发送数据的类型。一个可以发送int类型数据的channel一般写为chan int。

WaitGroup

实现阻塞

Add() 计数器增加

Done() 一个协程完成后计数器减一

Wait() 阻塞直到等待计数器归0

两种模式:

1.通过通信共享内存

2.通过共享内存实现通信

模式1,通过通信共享内存

开辟的不同的内存运行协程,协程之间使用cahnnel通信

package main

import (
	"fmt"
)

func CalSquare() {
	src := make(chan int)
	dest := make(chan int, 3)
	//生产者
	go func() {
		defer close(src)
		for i := 0; i < 10; i++ {
			src <- i
		}
	}()
	//消费者
	go func() {
		defer close(dest)
		for i := range src {
			dest <- i * i
		}
	}()
	for i := range dest {
		fmt.Println(i)
	}
}

func main() {
	CalSquare()

	//time.Sleep(time.Second)
}

运行结果

image.png

模式2.通过共享内存实现通信

不同的协程之间使用同一块内存,通过Lock加锁解决并发安全。

package main

import (
   "fmt"
   "sync"
   "time"
)

var (
   x    int64
   lock sync.Mutex
)


func main() {
   myAdd()

}

func myAdd() {
   var wg sync.WaitGroup
   wg.Add(5)
   x = 0
   for i := 0; i < 5; i++ {
      go func() {
         defer wg.Done()
         for i := 0; i < 2000; i++ {
            lock.Lock()
            x += 1
            lock.Unlock()
         }
      }()

   }
   wg.Wait()
   fmt.Println("withLock: ", x)

   wg.Add(5)
   x = 0
   for i := 0; i < 5; i++ {
      go func() {
         defer wg.Done()
         for i := 0; i < 2000; i++ {
            x += 1
         }
      }()

   }
   wg.Wait()
   fmt.Println("whithoutLoc: ", x)
}

运行结果

image.png