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

简介: Go语言进阶之并发编程 | 青训营笔记

前言

记录加入青训营的每一天的日笔记

并发编程

并发与并行的区别

并发:多线程程序在一个核的CPU上运行

并行:多线程程序在多个核的CPU上运行

Go可以充分发挥多核优势 高效运行

image.png

协程Goroutine

协程:用户态,轻量级线程 栈MB级别

线程:内核态,线程跑多个协程,栈KB级别

image.png

线程的创建、切换、停止较大地占用系统资源

协程的创建和调度由Go语言进行完成

通过开启协程快速打印hello goroutine案例:

package concurrence
import (
    "fmt"
    "time"
)
func hello(i int) {
    println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine() {
    for i := 0; i < 5; i++ {
        // go关键字作为创建协程的关键字
        go func(j int) {
            hello(j)
        }(i)
    }
    // 保证子协程运行完前主线程不退出
    time.Sleep(time.Second)
}

CSP(communicating sequential processes)并发模型

不同于传统的多线程通过共享内存来通信,CSP讲究的是“以通信的方式来共享内存”。

Do not communicate by sharing memory; instead, share memory by communicating. “不要以共享内存的方式来通信,相反,要通过通信来共享内存。”

Channel 缓冲通道

创建方式:

make(chan 元素类型, [缓冲大小])

通道是用来传递数据的一个数据结构,可以用于两个goroutine之间,通过传递一个指定类型的值来同步运行和通讯。

操作符<-用于指定通道的方向,实现发送or接收

若未指定方向,则为双向通道

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

image.png

通过两个Channel通道完成数字平方任务案例:

package concurrence
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 {
        //复杂操作
        println(i)
    }
}

注意:

  • 如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞。
  • 上述代码中之所以能够顺利从通道接收到数据,是因为每次遍历之前都通过关闭对应的通道后再进行的遍历接受数据

并发安全Lock

若采用共享内存实现通信,则会出现多个Goroutine同时操作一块内存资源的情况,这种情况会发生竞态问题(数据竞态)

Mutex互斥锁解决数据竞争

互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁。


package concurrence
import (
    "sync"
    "time"
)
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)
}
func ManyGoWait() {
    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()
}

使用互斥锁能够保证同一时间有且只有一个goroutine进入临界区,其他的goroutine则在等待锁;

当互斥锁释放后,等待的goroutine才可以获取锁进入临界区,多个goroutine同时等待一个锁时,唤醒的策略是随机的。

WaitGroup解决数据竞争

Go语言中除了可以使用通道(channel)和互斥锁进行两个并发程序间的同步外,还可以使用等待组进行多个任务的同步,等待组可以保证在并发环境中完成指定数量的任务 WaitGroup 值在内部维护着一个计数,此计数的初始默认值为零。


package concurrence
import (
    "fmt"
    "sync"
)
func HelloPrint(i int) {
    fmt.Println("Hello WaitGroup :", i)
}
func ManyGoWait() {
    var wg sync.WaitGroup
    wg.Add(5)
    for i := 0; i < 5; i++ {
        go func(j int) {
            defer wg.Done()
            HelloPrint(j)
        }(i)
    }
    wg.Wait()
}
func main() {
    ManyGoWait()
}

小结

今天学习到的内容还需要进一步的消化,我也是打算将并发编程这一块的内容熟悉透彻了再进行下一部分的课程学习。如果笔记中有错误的地方也希望掘友们可以及时的提出纠正。


目录
相关文章
|
22天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
36 7
|
22天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
22天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
96 71
|
21天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
102 67
|
24天前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
93 62
|
2天前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
29 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
26天前
|
并行计算 安全 Go
Go语言中的并发编程:掌握goroutines和channels####
本文深入探讨了Go语言中并发编程的核心概念——goroutine和channel。不同于传统的线程模型,Go通过轻量级的goroutine和通信机制channel,实现了高效的并发处理。我们将从基础概念开始,逐步深入到实际应用案例,揭示如何在Go语言中优雅地实现并发控制和数据同步。 ####
|
22天前
|
存储 Go
go语言中映射
go语言中映射
34 11
|
24天前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
33 12
|
23天前
|
Go 索引
go语言使用索引遍历
go语言使用索引遍历
29 9