GO进阶——解决高并发安全问题 | 青训营

95 阅读1分钟

GO——第二站

1.并发VS并行

  • 多线程程序在一个核cpu上运行

image.png

  • 多线程程序在多个核的cpu上运行

image.png

(1)Goroutine

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

内核态:多个线程,栈MB级别,一个线程并发跑多个协程

(2)举例

test1.go

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)
}

image.png

2.CSP(Communicating Sequential Processes)

(1).通过通信共享内容(go提倡)

(2).通过共享内容而实现通信

image.png

3.Channel

make(chan 元素类型,[缓冲大小]) make(chan int)//无缓冲大小 make(chan int 2)//大小为2的有缓冲通道 通过缓冲通道发送信息给终点,重点再对通道进行遍历,读取数据。 test1.go

func AB3(){
   //定义src是无缓冲大小的通道
   //定义dest是缓冲大小为3的通道
   src:=make(chan int)
   dest:=make(chan int,3)
   //A子协程
   go func(){
      defer close(src)
      for i:=0;i<10;i++{
         src <-i
      }
   }()
   //B子协程
   go func(){
      defer close(dest)
      for i:=range src{
         dest <- i*i
      }
   }()
   //主协程
   for i:=range dest{
      fmt.Println(i)
   }
}

4.并发安全

通过“加锁”操作,解决高并发问题。设置sleep阻塞并发操作1,但事先你并不知道上一个并发操作会在何时结束。在实际开发中,应尽量避免对并发数据的读取和使用。 test1.go

var(
   x int64
   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 Add(){
   x=0
   for i:=0;i<5;i++{
      go addWithoutLock()
   }
   time.Sleep(time.Second)
   println("withoutLock:",x)
   x=0
   for i:=0;i<5;i++{
      go addWithlock()
   }
   time.Sleep(time.Second)
   println("withLock:",x)
}

5.WaitGroup

实现并发任务的同步 Add():开启一个协程,该方法使计数器+1 Done():结束一个进程,该方法使计数器-1 Wait():阻塞直到计数器为0 test1.go

func ManyGoWait(){
   var wg sync.WaitGroup
   wg.Add(5)//计数器为5,表示有5个协程没有进行
   for i:=0;i<5;i++{
      go func(j int){
         defer wg.Done()//-1个协程
         hello(j)
      }(i)
   }
   wg.Wait()
}

6.依赖管理

GOPATH->Go Vendor->Go Module

$GOPATH

项目代码直接依赖src下的代码 go get 下载最新版本的包到src目录下 无法试下包的多版本控制

Go vendor

存放依赖的副本,解决了多个项目需要同一个package依赖的问题

image.png

Go Module

1.目标:定义版本规则和管理项目依赖关系 通过go.mod文件管理以来版本 通过go get/go mod指令工具管理依赖包

image.png 2.依赖管理三要素

(1)配置文件,描述依赖 go.mod MAJOR.{MAJOR}.{MINOR}.${PATCH} v1.17.12 编译时,满足本次构建的最低的兼容版本

(2)中心仓库管理依赖库 Proxy

image.png GOPROXY="proxy1.cn,https://proxy2.cn,…" Proxy1->Proxy2->direct

(3)本地工具 go get/mod

image.png

image.png

7.心得体会

今天又学到了很多知识,理解了"lock"在高并发中的巨大贡献,以及waitgroup在高并发中的合理使用。希望在日后的学习中,能够熟练运用本节知识,去处理类似于“生产——消费”以及“排队——买票”等问题。