后端实践--go并发编程 青训营

简介: 后端实践--go并发编程 青训营

后端实践--go并发编程 青训营

go的擅长领域就是高并发编程!!由于go语言的出现时间较晚,已经是并发编程较为普及的时代,所以go 语言在设计的时候就天生支持并发。

先了解一下并发和并行的概念。并发是指在一个时间段内多个任务共同推进,如核心上跑多个任务,一般会由于时间片轮转调度这多个任务在一个时间段内看上去同时在推进;而并行是指安排多个核心,每个核心去执行者多个任务中的一个或多个。

go 通过goroutine 实现并发。goroutine类似于线程,属于==用户态的线程==,比内核态的线程更轻量。goroutinego 运行时调度完成的,而内核态线程是由OS调度的。

一般goroutine 配合函数使用。相当于启动一个新的线程去执行这个函数。

channel: 在多个goroutine通信

1. goroutine

func hello(){
  fmt.Println("aaaa")
}
// 这里会创建一个主goroutine
// 主goroutine退出了,那么其他从属的goroutine也就退出了
func main(){
  // 启动一个新的goroutine(线程)执行这个函数
  go hello()
  // 主执行流正常往下执行
  fmt.Println("bbb")
  tmie.Sleep(time.Second)
}

等待goroutine 结束 (有点像信号量)

// 声明全局等待组变量
var wg sync.WaitGroup
func hello() {
  defer wg.Done() // 告知当前goroutine完成   -- 操作
  fmt.Println("hello")  
}
func main() {
  wg.Add(1) // 登记1个goroutine             ++操作
  go hello()
  fmt.Println("你好")
  wg.Wait() // 阻塞等待登记的goroutine完成    等到wg减到0
}

goroutine调度 --- GMP调度系统

G: goroutine 每执行一次go f()就创建一个 G,包含要执行的函数和上下文信息。

M: Machine 实际干活的。和内核线程是一一映射的关系。

P 管理者,管理goroutine。管理 goroutine 执行所需的资源,最多有 GOMAXPROCS 个。

GOMAXPROCS

// 设置执行当前任务的CPU核心数,默认是所有的核心
runtime.GOMAXPROCS(4)
runtime.NumCPU()

goroutineOS线程的区别

  1. 一个os线程可以对应多个goroutine
  2. go程序也可以同时使用多个os 线程
  3. 他们是多对多的关系

2. channel

就可以理解为一个类型。--- 引用类型!

三个常用的引用类型:切片、mapchan ==需要make 初始化。==

实现多 goroutine间通信。

有点像管道通信,遵循先入先出原则。

声明通道但没有初始化时其为nil,这时读取和写入都会都会阻塞。

自带访问控制机制:==通道开启时==,当通道为空时取值会阻塞住;当通道为满时写入也会阻塞住。通道关闭且有缓冲区时:不能写入,但是可以读取值直到读完。

// 声明一个channel管道,只能存放int类型的变量
var a chan int
var b chan []string
...
// 初始化(不带缓冲区)
a = make(chan int)
// 初始化(带缓冲区),代缓冲区的通道可以把接收的的数据先存到通道里
b = make(chan []string, 16)

chan 操作 <-

向通道里写:a <- 1

从通道里读:ch := <- a

关闭通道:close(a) , 这个别忘了!

// 循环取值
a := make(chan int, 10)
// 一样的:
// 若通道是开启的没有close,那么这里取完值后会阻塞!!!
// 只有通道关闭时取完值后会返回退出循环
for i := range a{
  // ...
}
// 手动判断停止
for{
  // 若通道是开启的没有close,那么这里取完值后会阻塞!!!
  // 只有通道关闭时取完值后会返回:对应类型的零值和 false
  x,ok := <- a
  if !ok{
    // 读完了
    break
  }
  // ...
}

确保只执行一次。

var once sync.Once
// ...
// 确保只关闭一次,关闭已经关闭了的chan会引发panic!!
once.Do(func(){ close(a) })

单向通道

通常用于函数参数,限制为只允许读取或只允许写入的通道。

// 只能写入数据的通道
var a chan<- int
// 只能读取数据的通道
var b <-chan int

通道仅用来作为标记等时可以这样用,节省空间。

// 通道类型是空结构体,更节省空间!
var notice = make(chan struct{}, 10)
// ...
// 向notice通道里写入。  struct{} 是类型,再加一个 {} 表示实例化
notice <- struct{}{}

3. worker pool (goroutine 池)

就是开启多个 goroutine 竞争执行任务。

4. select 多路复用

同一时刻有多个通道,选择其中某一个执行。

让其他未满足条件的通道同时等待,提高效率。

a := make(chan int, 1)
select{
  // 哪个满足条件就执行哪一个,有多个条件满足时随机执行一个!
  case x := <- a: 
    // ...
  case a <- 10:
    // ... 
}

以上就是go并发编程的简单知识,另外涉及到并发,就还有互斥锁和读写锁等各类锁的使用以及线程互斥和线程同步的知识,这里就不赘述了。

相关文章
|
9天前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
8天前
|
存储 监控 安全
构建现代后端系统:架构与实践
【8月更文挑战第12天】本文旨在探讨构建现代后端系统时需考虑的架构和实践问题。我们将通过分析现代后端系统的核心组件、设计原则、以及如何应对可扩展性、安全性、性能等挑战,提供一个全面的视角。文章不包含代码示例,而是侧重于理论与策略层面的讨论,以期为后端开发人员提供有价值的参考和指导。
|
8天前
|
设计模式 存储 安全
深入理解后端开发:从基础到高级实践
在数字化时代,后端开发是构建强大、可靠和高效软件系统的核心。本文将引导读者从基本概念出发,逐步深入到后端开发的高级实践,包括设计模式、性能优化以及安全性考量。通过深入浅出的解释和实例演示,旨在帮助初学者和有经验的开发者巩固知识、拓展视野,并激发对后端开发深层次理解的兴趣。
|
8天前
|
存储 SQL 缓存
构建高性能后端服务的策略与实践
【8月更文挑战第13天】在数字化时代,后端服务的高效性对于企业至关重要。本文深入探讨了如何通过合理设计、优化数据库操作以及应用缓存技术等策略来提升后端服务性能。同时,也强调了监控和调优的重要性,并指出了团队协作在性能优化中的作用。
23 3
|
7天前
|
安全 Java 数据库
后端开发的艺术与实践
在数字化时代的浪潮中,后端开发如同一位默默无闻的画家,在幕后精心绘制着互联网世界的绚丽多彩。本文将带你走进后端开发的世界,从基础概念到技术选型,再到性能优化和安全防护,一起探索那些隐藏在代码背后的艺术与智慧。
|
8天前
|
存储 测试技术 数据库
探索后端开发:从基础到高级实践
在这篇文章中,我们将一起踏上一段激动人心的旅程,穿越后端开发的广阔天地。无论你是刚踏入这个领域的新手,还是希望巩固和扩展知识的资深开发者,本文都将是你的指南针。我们将从后端开发的基础知识讲起,涵盖语言选择、数据库设计、服务器架构等核心概念。随后,深入探讨高级实践,包括微服务架构、容器化技术以及自动化测试策略。最后,我们将讨论如何保持技术热情,持续学习,并对未来趋势保持敏锐的洞察力。让我们一起解锁后端开发的秘密,构建强大而灵活的系统吧!
|
6天前
|
算法 NoSQL 中间件
go语言后端开发学习(六) ——基于雪花算法生成用户ID
本文介绍了分布式ID生成中的Snowflake(雪花)算法。为解决用户ID安全性与唯一性问题,Snowflake算法生成的ID具备全局唯一性、递增性、高可用性和高性能性等特点。64位ID由符号位(固定为0)、41位时间戳、10位标识位(含数据中心与机器ID)及12位序列号组成。面对ID重复风险,可通过预分配、动态或统一分配标识位解决。Go语言实现示例展示了如何使用第三方包`sonyflake`生成ID,确保不同节点产生的ID始终唯一。
go语言后端开发学习(六) ——基于雪花算法生成用户ID
|
12天前
|
存储 安全 Go
Go 并发编程精粹:掌握通道(channels)的艺术
Go 并发编程精粹:掌握通道(channels)的艺术
|
7天前
|
JSON 缓存 监控
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
Viper 是一个强大的 Go 语言配置管理库,适用于各类应用,包括 Twelve-Factor Apps。相比仅支持 `.ini` 格式的 `go-ini`,Viper 支持更多配置格式如 JSON、TOML、YAML
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
|
12天前
|
Go 开发者
使用Go语言进行高效并发编程
【8月更文挑战第9天】Go语言的并发模型以其简洁和高效著称,通过goroutines和channels,开发者可以轻松地编写出高性能的并发程序。此外,Go标准库还提供了丰富的并发原语和工具,如WaitGroup和Context,进一步简化了并发编程的复杂性。掌握Go语言的并发编程技巧,对于开发高性能、高并发的应用至关重要。希望本文能帮助你更好地理解和使用Go语言进行并发编程。