Go语言:并发编程详解 | 青训营

87 阅读2分钟

并发编程

并发VS并行

并发(concurrency)

把任务在不同的时间点交给处理器进行处理。在同一时间点,任务并不会同时运行。

image.png

并行(parallelism)

把每一个任务分配给每一个处理器独立完成。在同一时间点,任务一定是同时运行。

image.png

协程-Goroutine

image.png

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

线程:内核态、一个线程可以跑多个协程、栈MB级别

使用协程

func Hello(i int) { 
    fmt.Println("Hello:" + fmt.Sprint(i)) 
} 
func main() { 
    for i := 0; i < 5; i++ { 
        //开启协程 
        go func(j int) { 
            Hello(j) 
        }(i) 
    } 
    //使用定时阻塞 
    time.Sleep(time.Second) 
}

协程通信

官方推荐使用通道通信

image.png

通道-channel

通道(channel)是用来传递数据的一个数据结构。

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

image.png

// 通道关闭之前会进行阻塞等待的操作 
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() 
}

并发安全-Lock锁

在并发编程中,锁(Lock)是用来保护共享资源的一种机制。在Go语言中,锁是实现并发的重要工具之一。它可以确保在多个协程中同时访问共享资源时,只有一个协程能够读取或修改这些资源。本文将介绍Go语言中锁的使用方法,帮助读者更好地理解并发编程。

//并发安全(Lock) 
var ( 
    x int64 
    //使用Lock 
    x_Lock sync.Mutex 
) 
func AddWithLock() { 
    for i := 0; i < 2000; i++ { 
    //上锁 
    x_Lock.Lock() 
    x += 1 
    //开锁 
    x_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) 
    fmt.Println("AddWithoutLock:", x) 
    x = 0 
    for i := 0; i < 5; i++ { 
        go AddWithLock() 
    } 
    time.Sleep(time.Second) 
    fmt.Println("AddWithLock:", x) 
} 

func main() { 
    Add() 
}

WaitGroup的使用

用来阻塞主协程,可以等待所有协程执行完。

总共三个方法

Add(n)【n为总共要等待的协程数】

Done【在协程中调,相当于Add(-1)】

Wait【等待阻塞结束】

func Many() { 
    var wg sync.WaitGroup 
    //添加协程数量 
    wg.Add(5) 
    for i := 0; i < 5; i++ { 
        go func(j int) { 
        //协程数量减一 
        defer wg.Done() 
        fmt.Println("hello:" + fmt.Sprint(j)) 
        }(i)
    } 
    //阻塞等待协程结束 
    wg.Wait() 
} 
func main() { 
    Many() 
}