Go语言进阶 | 青训营笔记

46 阅读1分钟

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

Goroutine

首先了解一下进程、线程、协程这三个的概念。

  • 进程:简单来说用户运行程序时,就会产生进程,同一个程序会产生多个进程。
  • 线程:有时被称为轻量级进程,是执行流的最小单元。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源。
  • 协程:又称微线程与子例程(或者称为函数)一样,协程(coroutine)也是一种程序组件。

线程与协程区别

  • 线程:用户态、轻量级线程、栈MB级别
  • 协程:内核态、线程里可以跑多个协程,栈KB级别
func hello(i int) {
   println("hello goroutine" + fmt.Sprint(i))
}

func HelloGoRoutine() {
   for i := 0; i < 5; i++ {
      go func(j int) { //启动协程
         hello(j)
      }(i)
   }
   time.Sleep(time.Second) //主线程休眠,防止协程未执行,主线程结束。
}

go启动协程的方式就是使用关键字go,后面一般接一个函数或者匿名函数。

CSP

go 是通过通信共享内存,而不是通过共享内存而实现通信。

Channel(管道)

make(chan 元素类型,[缓冲区大小])

  1. 无缓冲管道:make(chan int)
  2. 有缓冲管道:make(cahn int 2)
func Cal() {
   src := make(chan int) //无缓冲通道
   dest := make(chan int ,3)//有缓冲通道
   //相当于生产
   go func() { //协程A发送0~9数字
      defer close(src) //延迟资源关闭
      for i :=0;i<9;i++{
         src <- i
      }
   }()
   //相当于消费
   go func() { //协程B计算输入数字的平方
      defer close(dest)//延迟资源关闭
      for i :=range src{ //遍历src
         dest <- i * i
      }
   }()
   //主协程输出最后数的平方
   for i := range dest{
      println(i)
   }
}

输出结果:

0 1 4 9 16 25 36 49 64

并发安全Lock

var x int64
var lock sync.Mutex

// 加锁的方法
func addWithLock() {
   for i := 0; i < 2000; i++ {
      lock.Lock() //加锁
      x += 1
      lock.Unlock() //释放锁
   }
}
// 未加锁的方法
func addWithoutLock() {
   for i := 0; i < 2000; i++ {
      x += 1
   }
}
func main() {
   x = 0
   //5 个协程并发
   for i := 0; i < 5; i++ {
      go addWithLock() //加锁
   }
   time.Sleep(time.Second) //休眠
   println("addWithLock", x)

   for i := 0; i < 5; i++ {
      go addWithoutLock() //未加锁
   }
   time.Sleep(time.Second)//休眠
   println("addWithoutLock", x)
}

addWithLock 10000; addWithoutLock 7919

WaitGroup

func HelloGoRoutine() {
   var wg sync.WaitGroup
   wg.Add(5) //计数器
   for i := 0; i < 5; i++ {
      go func(j int) { //启动协程
         defer wg.Done() //计数器-1
         hello(j)
      }(i)
   }
   wg.Wait() //用于阻塞,直到计数器为0
}

测试

参考文章:

软件测试(理论基础)