谈到并发,首先想到的就是进程,线程与协程,线程是一个争对内核态的一个程序,它是由多个协程组成的,而协程是一个轻量化的线程它是针对用户态进行的。与传统的系统级线程和进程相比,协程的最大优势在于其"轻量级",可以轻松创建上百万个而不会导致系统资源衰竭,而线程和进程通常最多也不能超过1万的。这也是协程也叫轻量级线程的原因 。
go中使用Goroutine来实现并发concurrently,与线程相比,Goroutines非常便宜。它们只是堆栈大小的几个kb,堆栈可以根据应用程序的需要增长和收缩,而在线程的情况下,堆栈大小必须指定并且是固定的Goroutines被多路复用到较少的OS线程。在一个程序中可能只有一个线程与数千个Goroutines。如果线程中的任何Goroutine都表示等待用户输入,则会创建另一个OS线程,剩下的Goroutines被转移到新的OS线程。所有这些都由运行时进行处理,我们作为程序员从这些复杂的细节中抽象出来,并得到了一个与并发工作相关的干净的API。当使用Goroutines访问共享内存时,通过设计的通道可以防止竞态条件发生。通道可以被认为是Goroutines通信的管道。在协程go一般是通过channel共享内存的方式,实现双方通信。
Channel的创建ch := make(chan int ,[缓冲区大小])。Channel的应用: `func Cal(){ src :=make(chan int) //创建一个数字协程
dest:=make(chan int,3) //创建一个带缓冲区的协程
go func(){//启动A协程
defer close(src) //关闭协程
for i:=0;i<10;i++
{
Src<-i
}()
go func(){//启动B协程
defer close(dest) //关闭协程
for i:=0:=range src //遍历创建的数字
{
dest<-i*i
}()
for i:=range dest{
println(i)
}
}
} `
但是其实在并发的过程中,非常容易出现安全问题,因此针对并发安全,go通过使用Lock方法可将资源区锁住,使得资源不会出现问题。WaitGroup 是 sync 包用来做任务编排的一个并发原语,主要用来解决一个 goroutine 等待多个 goroutine 执行完成的场景。WaitGroup 和 Java 中的 CyclicBarrier、CountDownLatch 非常类似。比如我们有一个主任务在执行,执行到某一点时需要并行执行三个子任务,并且需要等到三个子任务都执行完后,再继续执行主任务。那我们就需要设置一个检查点,使主任务一直阻塞在这,等三个子任务执行完后再放行。
WaitGroup 一共有三个方法: 1.Add 方法用于设置 WaitGroup 的计数值,可以理解为子任务的数量 2.Done 方法用于将 WaitGroup 的计数值减一,可以理解为完成一个子任务 3.Wait 方法用于阻塞调用者,直到 WaitGroup 的计数值为0,即所有子任务都完成 正常来说,我们使用的时候,需要先确定子任务的数量,然后调用 Add() 方法传入相应的数量,在每个子任务的协程中,调用 Done(),需要等待的协程调用 Wait() 方法