Go语言并发编程 | 青训营笔记

71 阅读3分钟
这是我参与「第五届青训营 」伴学笔记创作活动的第2天。

第一天我们已经接触了go语言的基本语法,今天的主要是记录课程当中的并发编程内容。

一、go语言并发编程特点

广义上的并发是指多线程程序在一个核的cpu上运行,主要是通过切换时间片来实现同时运行,并行是多线程程序直接利用多核来实现运行。而go语言是可以设置使用的核心数,充分发挥多核计算机的优势,提高运行效率。

二、详细知识点

1.goroutine

并发调用函数可以在函数前面加上go关键字,相当于给函数创建一个协程运行。time.sleep(time.Second)可以强制主线程等待上面的进程结束再往下运行。

for i := 0;i<5;i++ {
    go hello(i)
}
time.sleep(time.Second)
2.有缓冲通道进行协程通信

这里协程A会生产一个数字提供给src,B协程就会将A协程生产的数据src遍历读取并对其进行平方处理(实现线程和线程的通信)。主线程会对B线程中dest获取的平方数据进行读取。缓冲是指make(chan int, n)中n的参数,如果n为0是不带缓冲。而且dest是有缓冲的,比如dest里面是[0,1,4]时,此时dest已满,src写不进去,当主线程读取0以后,dest就能把下一个src也就是3*3=9写入dest,此时dest就变为[1,4,9]。

src := make(chan int)
dest := make(chan int, 3)
go func() {
    defer close(src)
    for i := 0; i < 10; i++ {
        src <- i
    }
}()//协程A
go func() {
    defer close(dest)
    for i := range src {
         dest <- i * i
    }
}()//协程B
for i := range dest {
    println(i)
}
3.并发安全lock

这里代码是对全局变量x执行2000次+1操作,由5个协程并发进行。由两种方式运行,一种是调用lock进行加锁运行,一种是直接运行,最终加锁的结果x为10000,不加锁的结果x为5312(不加锁结果是随机的)。不加锁的结果比较好理解,主要是多个协程同时调用x+1的操作(可能同时进行的是3个协程,也可能是4个,每个协程调用x+1的时间我们也无法确定),而x能够记录的值只有一个,导致同时进行的x+1操作只有1个是有效的,其他全是无效操作。加锁是对x+1操作时进行控制,不让其他协程进行x+1的操作,这样能够保证5个协程执行的所有x+1操作都是有效的。

package main

import (
    "sync"
    "time"
)

var (
    x    int64
    lock sync.Mutex
)

func main(){
    x = 0
    for i:=0;i<5;i++{
        go func(){
            for i:=0;i<2000;i++{
                lock.Lock()
                x+=1
                lock.Unlock()
            }
        }()
    }
    time.Sleep(time.Second)
    println("WithLock:",x)
    x = 0
    for i:=0;i<5;i++{
        go func(){
            for i:=0;i<2000;i++{
                x+=1
            }
        }()
    }
    time.Sleep(time.Second)
    println("WithoutLock:",x)
}
4.等待并发任务执行

Sync.WaitGroup是一个计数器功能,能够让主协程阻塞等待所有协程结束。主要操作是:wait阻塞主协程等待协程结束;add能够让计数器增加,这里add(5)是指有5个协程阻塞主协程进行;每个协程执行结束后要进行done操作使协程减一。

var wg sync.WaitGroup
wg.Add(5)
for i := 0;i<5;i++ {
    go func(j int){
        defer wg.Done()
        hello(j)
    }(i)
}
wg.Wait()

总结

本节课主要是学习了一些go语言并发编程的方法。

参考

Go语言并发详解_小熊coder的博客-CSDN博客_go 并发

Golang协程之了解管道的缓存能力_恒生LIGHT云社区的博客-CSDN博客_go 管道缓存可以变化么