[ go语言进阶总结 | 青训营笔记 ]

73 阅读2分钟

一,Goroutine

什么是goroutine?

goroutine是Go语言中的一种轻量级线程,它可以在单个线程中运行,并且可以由Go语言的运行时系统进行调度。goroutine的启动非常快,只需要几个字节的栈空间,因此可以并发地启动大量的goroutine,从而实现高效的并发编程。在Go语言中,使用关键字go可以启动一个goroutine。

这也是go语言适合高并发的一个主要原因。
如何使用goroutine?

基本用法就是在函数的前面加一个go关键字,就可以为该函数创建一个协程

接下来是一个测试代码,简述了goroutine的基本使用方法

package main

import (
   "fmt"
   "time"
)

func main() {
   // 启动一个goroutine来执行计算任务
   go compute()

   // 在主goroutine中执行其他任务
   for i := 0; i < 10; i++ {
      fmt.Println("Main goroutine is working...")
      time.Sleep(time.Millisecond * 500)
   }
}

func compute() {
   // 在新的goroutine中执行计算任务
   for i := 0; i < 5; i++ {
      fmt.Println("Compute goroutine is working...")
      time.Sleep(time.Millisecond * 500)
   }
}

在这个例子中,我们启动了一个新的goroutine来执行计算任务,同时在主goroutine中执行其他任务。执行结果如下

image.png 可以看出子协程与主协程是并行执行的。

注意: time.Sleep(time.Millisecond * 500)的作用是让当前协程秀逸休息一段时间,以便给其他协程执行机会。

二,channel

goroutine间的通信(csp)有两种,但go更加推荐第一种,也就是通过通信共享内存,在通信中就需要用到channel,channel的基本用法如下:

在Go语言中,channel是一种原生类型,用于goroutine之间的通信和同步。channel可以看作是一条管道,goroutine可以通过它发送和接收数据。channel有两个基本操作:发送和接收。发送操作使用<-符号,例如: ch <- data // 将数据data发送到channel ch中 接收操作使用<-符号,例如: data := <- ch // 从channel ch中接收数据,并将其保存到变量data中 channel可以是有缓冲的,也可以是无缓冲的。无缓冲的channel在发送和接收时会被阻塞,直到另一个goroutine准备好接收或发送数据。有缓冲的channel则可以在缓冲区未满时发送数据,或在缓冲区未空时接收数据,否则也会被阻塞。 通过使用channel,我们可以实现goroutine之间的通信和同步,从而实现更加高效和安全的并发编程。例如,我们可以使用channel来实现生产者-消费者模式,或者实现多个goroutine之间的任务协作。

channel的创建需要使用make关键字,有如下两种形式,一种是创建带缓冲区的channel,一种是创建不带缓冲区的channel。

无缓冲通道 make(chan int)
有缓冲通道 make(chan int,2)

以下例子是一个关于channel的使用实例

package main

import "fmt"

func CalSquare() {
   src := make(chan int)
   dest := make(chan int, 3)

   go func() {
      defer close(src)
      for i := 1; 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()
}

两个协程之间通过src完成了通信

并发安全Lock

Mutex是Go语言中的一个同步原语,用于实现互斥锁,即一次只能有一个协程访问共享资源。Mutex的全称是Mutual Exclusion,意为互斥。 在Go语言中,多个协程可以同时运行,如果多个协程同时访问共享资源,可能会导致数据竞争和不确定的行为。为了避免这种情况,我们可以使用Mutex来保护共享资源。 Mutex的使用非常简单,可以通过sync包中的Mutex类型来创建一个互斥锁,然后使用LockUnlock方法来加锁和解锁。

相关代码

/*
*
准备开启多个这样的协程,通过上锁,开锁,使各个协程互不干扰
*/
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 Add() {
   x = 0
   for i := 0; i < 5; i++ {
      go addWithLock()
   }
   time.Sleep(time.Second)
   println("WithLock", x)
   x = 0
   for i := 0; i < 5; i++ {
      go addWithoutLock()
   }
   time.Sleep(time.Second)
   println("WithoutLock", x)
}

func main() {
   //CalSquare()
   Add()
}