当前位置: 首页 > news >正文

Golang开发

Golang

文章目录

  • Golang
    • 预备技术
      • 一、算法与数据结构
        • 第1章:基础算法
        • 第2章:数据结构
        • 第3章:搜索与图论
        • 第4章:数论
        • 第5章:动态规划
        • 第6章:贪心
        • 第7章:算法竞赛入门
      • 二、Linux操作系统与Shell编程
      • 三、计算机操作系统
      • 四、计算机组成原理
      • 五、计算机网络
      • 六、Docker:云原生核心技术之一
    • Go 开发编程实战
      • 一、基本语法
        • 第1章:走进Golang
        • 第2章:变量与数据类型
        • 第3章:运算符
        • 第4章:流程控制
        • 第5章:函数
        • 第6章:错误处理
        • 第7章:数组
        • 第8章:切片
        • 第9章:映射
        • 第10章:面向对象
        • 第11章:文件的操作
        • 第12章:协程和管道
          • 1. 程序、进程、线程、协程
            • (1)程序 (program)
            • (2)进程 (process)
            • (3)线程 (thread)
            • (4)协程 (goroutine)
          • 2. 协程入门
            • (1)案例
          • 3. 主死从随
            • (1)主死从随
          • 4. 启动多个协程
            • (1)案例
          • 5. 使用WaitGroup控制协程退出
            • (1)WaitGroup的作用
            • (2)主要方法
            • (3)案例代码
          • 6. 多个协程操纵统一数据案例(互斥锁)
            • (1)案例
          • 7. 读写锁的使用
            • (1)互斥锁
            • (2)读写锁
            • (3)案例
          • 8. 管道介绍
            • (1)管道(channel)特质介绍
          • 9. 管道入门案例
            • (1)管道的定义
            • (2)案例
          • 10. 管道的关闭
            • (1)管道的关闭
            • (2)案例
          • 11. 管道的遍历
            • (1)管道的遍历
          • 12. 协程和管道协同工作的案例
          • 13. 声明只读只写管道
          • 14. 管道的阻塞
          • 15. select功能
          • 16. defer + recover机制处理错误
        • 第13章:网络编程
        • 第14章:反射
      • 二、Golang进阶 - 网络通信
      • 三、Golang进阶 - 并发编程
    • Go Web开发之前端技术实战
      • 一、Go Web前置 - Go Module
      • 二、Go Web前置 - HTML
      • 三、Go Web前置-CSS
      • 四、Go Web前置-JS
      • 五、Go Web前置-JQuery
      • 六、前端技术之Vue框架
    • GORM及数据库
      • 一、GORM前置:MySQL
      • 二、MySQL性能调优与架构设计
      • 三、GORM
    • Go开发应用中间件
      • 一、Redis_高效的NoSQL数据库
      • 二、Redis缓存数据库进阶
      • 三、Redis之go编程实战
      • 四、消息中间件-Kafka实战
      • 五、Kafka之go编程实战
      • 六、RocketMQ基础实战版
      • 七、NoSQL-MongoDB实战
      • 八、分布式文件存储系统Minio
    • 全文检索 ES
      • 一、Elasticsearch核心知识篇
    • Go Web开发之企业级框架
      • 一、Web框架
      • 二、Gin深入实战
      • 三、Beego框架开发实战
      • 四、微服务架构
      • 五、Go框架开发
      • 六、Kong入门与实战
      • 七、Logrus日志
    • 企业级项目实战

预备技术

一、算法与数据结构

第1章:基础算法

https://blog.csdn.net/m0_52806260/article/details/125519736

第2章:数据结构

https://blog.csdn.net/m0_52806260/article/details/125592926

第3章:搜索与图论

https://blog.csdn.net/m0_52806260/article/details/125771347

第4章:数论

https://blog.csdn.net/m0_52806260/article/details/125843269

第5章:动态规划

https://blog.csdn.net/m0_52806260/article/details/125459689

第6章:贪心

https://blog.csdn.net/m0_52806260/article/details/125987376

第7章:算法竞赛入门

https://blog.csdn.net/m0_52806260/article/details/146226657

二、Linux操作系统与Shell编程

https://blog.csdn.net/m0_52806260/article/details/126068791

三、计算机操作系统

四、计算机组成原理

五、计算机网络

六、Docker:云原生核心技术之一

Go 开发编程实战

一、基本语法

第1章:走进Golang
第2章:变量与数据类型
第3章:运算符
第4章:流程控制
第5章:函数
第6章:错误处理
第7章:数组
第8章:切片
第9章:映射
第10章:面向对象
第11章:文件的操作
第12章:协程和管道
1. 程序、进程、线程、协程
(1)程序 (program)
  • 程序是为完成特定任务、用某种语言编写的一组指令的集合,是一段静态的代码。 (程序是静态的)
(2)进程 (process)
  • 是程序的一次执行过程。正在运行的一个程序,进程作为资源分配的单位,在内存中会为每个进程分配不同的内存区域。 (进程是动态的)是一个动的过程 ,进程的生命周期 : 有它自身的产生、存在和消亡的过程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(3)线程 (thread)
  • 进程可进一步细化为线程, 是一个程序内部的一条执行路径。
  • 若一个进程同一时间并行执行多个线程,就是支持多线程的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(4)协程 (goroutine)
  • 又称为微线程,纤程,协程是一种用户态的轻量级线程
  • 作用:在执行A函数的时候,可以随时中断,去执行B函数,然后中断继续执行A函数(可以自动切换),注意这一切换过程并不是函数调用(没有调用语句),过程很像多线程,然而协程中只有一个线程在执行(协程的本质是个单线程)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 对于单线程下,我们不可避免程序中出现io操作,但如果我们能在自己的程序中(即用户程序级别,而非操作系统级别)控制单线程下的多个任务能在一个任务遇到io阻塞时就将寄存器上下文和栈保存到某个其他地方,然后切换到另外一个任务去计算。在任务切回来的时候,恢复先前保存的寄存器上下文和栈,这样就保证了该线程能够最大限度地处于就绪态,即随时都可以被cpu执行的状态,相当于我们在用户程序级别将自己的io操作最大限度地隐藏起来,从而可以迷惑操作系统,让其看到:该线程好像是一直在计算,io比较少,从而会更多的将cpu的执行权限分配给我们的线程(注意:线程是CPU控制的,而协程是程序自身控制的,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级)
2. 协程入门
(1)案例
  • 请编写一个程序,完成如下功能:
    (1)在主线程中,开启一个goroutine,该goroutine每隔1秒输出"hello golang"
    (2)在主线程中也每隔一秒输出"good bye golang",输出10次后,退出程序
    (3)要求主线程和goroutine同时执行
  • 实现代码
package main

import (
	"fmt"
	"time"
)

func test() {
	for i := 1; i <= 10; i++ {
		fmt.Println("hello golang")
		time.Sleep(1 * time.Second) // 阻塞一秒
	}
}

func main() {
	go test() // 开启一个协程:go + 函数名
	// 主线程
	for i := 1; i <= 10; i++ {
		fmt.Println("good bye golang")
		time.Sleep(1 * time.Second) // 阻塞一秒
	}
	return
}

  • 运行结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 执行流程示意图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3. 主死从随
(1)主死从随
  • 如果主线程退出了,则协程即使还没有执行完毕,也会退出
  • 当然协程也可以在主线程没有退出前,就自己结束了,比如完成了自己的任务
  • 验证代码
package main

import (
	"fmt"
	"strconv"
	"time"
)

func test() {
	for i := 1; i <= 1000; i++ {
		fmt.Println("hello golang" + strconv.Itoa(i))
		time.Sleep(1 * time.Second) // 阻塞一秒
	}
}

func main() {
	go test() // 开启一个协程:go + 函数名
	// 主线程
	for i := 1; i <= 10; i++ {
		fmt.Println("good bye golang" + strconv.Itoa(i))
		time.Sleep(1 * time.Second) // 阻塞一秒
	}
	return
}

  • 执行结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4. 启动多个协程
(1)案例
package main

import (
	"fmt"
	"time"
)

func main() {
	// 匿名函数 + 外部变量 = 闭包
	for i := 1; i <= 5; i++ {
		go func(n int) {
			fmt.Printf("这是%d号协程\n", n)
		}(i)
	}

	time.Sleep(2 * time.Second) // 避免主死从随
}

5. 使用WaitGroup控制协程退出
(1)WaitGroup的作用

WaitGroup用于等待一组线程的结束。父线程调用Add方法来设定应等待的线程的数量。每个被等待的线程在结束时应调用Done方法。同时,主线程里可以调用Wait方法阻塞至所有线程结束。—> 解决主线程在子协程结束后自动结束

(2)主要方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(3)案例代码
  • Add/Done/Wait
package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func main() {

	// 启动五个协程
	for i := 1; i <= 5; i++ {
		wg.Add(1) // 协程开始
		go func(n int) {
			fmt.Printf("这是%d号协程\n", n)
			wg.Done() // 协程结束
		}(i)
	}
	wg.Wait() // 阻塞等待协程全部完成
}

  • 如果忘记计数器减1,可以提前defer:
package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func main() {

	// 启动五个协程
	for i := 1; i <= 5; i++ {
		wg.Add(1) // 协程开始
		go func(n int) {
			defer wg.Done() // 提前写defer,防止忘记计数器-1
			fmt.Printf("这是%d号协程\n", n)
			/*
				其余代码
				其余代码
				其余代码
				其余代码
				其余代码
			*/
		}(i)
	}
	wg.Wait() // 阻塞等待协程全部完成
}

  • 可以最开始在知道协程次数的情况下先Add操作:
package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func main() {
	wg.Add(5) // 预先设置协程数
	// 启动五个协程
	for i := 1; i <= 5; i++ {
		go func(n int) {
			defer wg.Done() // 提前写defer,防止忘记计数器-1
			fmt.Printf("这是%d号协程\n", n)
			/*
				其余代码
				其余代码
				其余代码
				其余代码
				其余代码
			*/
		}(i)
	}
	wg.Wait() // 阻塞等待协程全部完成
}

注意:Add中加入的数字和协程的次数一定要保持一致

6. 多个协程操纵统一数据案例(互斥锁)
(1)案例
package main

import (
	"fmt"
	"sync"
)

var totalNum int
var wg sync.WaitGroup

func add() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		totalNum++
	}
}
func sub() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		totalNum--
	}
}
func main() {
	wg.Add(2) // 预先设置协程数
	// 启动五个协程
	go add()
	go sub()
	wg.Wait() // 阻塞等待协程全部完成s
	fmt.Println(totalNum)
}

  • 结果:在理论上,这个totalNum结果应该是0 ,无论协程怎么交替执行,最终想象的结果就是0,但是事实上:不是

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 问题出现的原因:(图解为其中一种可能性)外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 解决问题:确保一个机制:一个协程在执行逻辑的时候另外的协程不执行 ----> 锁的机制—> 加入互斥锁

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 代码实现
package main

import (
	"fmt"
	"sync"
)

var totalNum int
var wg sync.WaitGroup
var lock sync.Mutex

func add() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		lock.Lock() // 上锁
		totalNum++
		lock.Unlock() // 解锁
	}
}
func sub() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		lock.Lock() // 上锁
		totalNum--
		lock.Unlock() // 解锁
	}
}
func main() {
	wg.Add(2) // 预先设置协程数
	// 启动五个协程
	go add()
	go sub()
	wg.Wait() // 阻塞等待协程全部完成s
	fmt.Println(totalNum)
}

7. 读写锁的使用

golang中sync包实现了两种锁 Mutex (互斥锁)和 RWMutex(读写锁)

(1)互斥锁
  • 其中Mutex为互斥锁,Lock()加锁,Unlock()解锁,使用Lock()加锁后,便不能再次对其进行加锁,直到利用Unlock()解锁对其解锁后,才能再次加锁.适用于读写不确定场景,即读写次数没有明显的区别
  • 性能、效率相对来说比较低,因为大部分场景都是读多写少
(2)读写锁
  • RWMutex是一个读写锁,其经常用于读次数远远多于写次数的场景.
  • 在读的时候,数据之间不产生影响,写和读之间才会产生影响
(3)案例
package main

import (
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup // 只定义无需赋值
// 加入读写锁:
var lock sync.RWMutex

func read() {
	defer wg.Done()
	lock.RLock() //如果只是读数据,那么这个锁不产生影响,但是读写同时发生的时候,就会有影响
	fmt.Println("开始读取数据")
	time.Sleep(1 * time.Second)
	fmt.Println("读取数据成功")
	lock.RUnlock()
}

func write() {
	defer wg.Done()
	lock.Lock()
	fmt.Println("开始修改数据")
	time.Sleep(time.Second * 5)
	fmt.Println("修改数据成功")
	lock.Unlock()
}

func main() {
	wg.Add(6)
	// 启动协程 ---> 场合:读多写少
	for i := 0; i <= 5; i++ {
		go read()
	}
	go write()
	wg.Wait()
}

  • 运行结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

8. 管道介绍
(1)管道(channel)特质介绍
  • 管道本质就是一个数据结构——队列
  • 数据是先进先出
  • 自身线程安全,多协程访问时,不需要加锁,channel本身就是线程安全的
  • 管道有类型的,一个string的管道只能存放string类型数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

9. 管道入门案例
(1)管道的定义

var 变量名 chan 数据类型

  • chan管道关键字
  • 数据类型指的是管道的类型,里面放入数据的类型,管道是有类型的,int类型的管道只能写入整数int
  • 管道是引用类型,必须初始化才能写入数据,即make后才能使用
(2)案例
package main

import "fmt"

func main() {
	// 定义管道,声明管道 ---> 定义一个int类型的管道
	var intChan chan int
	// 通过make进行初始化:管道可以存放3个int类型的数据
	intChan = make(chan int, 3)
	// 证明管道是引用类型
	fmt.Printf("intChan:%v\n", intChan)
	// 向管道存放数据
	intChan <- 10
	num := 20
	intChan <- num
	intChan <- 40
	// 注意:不能存放大于容量的数据

	num1 := <-intChan
	num2 := <-intChan
	num3 := <-intChan

	// 输出管道的长度
	fmt.Printf("管道的实际长度:%v,管道的容量是:%v\n", len(intChan), cap(intChan))

	fmt.Println(num1)
	fmt.Println(num2)
	fmt.Println(num3)

	// 注意:在没有使用协程的情况下,如果管道的数据已经全部取出,那么再取就会报错:
	//num4 := <-intChan
	//fmt.Println(num4)
}

10. 管道的关闭
(1)管道的关闭
  • 使用内置函数close可以关闭管道,当管道关闭后,就不能再向管道写数据了,但是仍然可以从该管道读取数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(2)案例
package main

import "fmt"

func main() {
	// 定义管道,声明管道 ---> 定义一个int类型的管道
	var intChan chan int
	// 通过make进行初始化:管道可以存放3个int类型的数据
	intChan = make(chan int, 3)
	// 在管道中存放数据:
	intChan <- 10
	intChan <- 20
	
    // 关闭管道:
	close(intChan)
    
	// 再次写入数据:--->报错
	// intChan<- 30
	// 当管道关闭后,读取数据是可以的:
	num := <-intChan
	fmt.Println(num)
}

11. 管道的遍历
(1)管道的遍历
  • 管道支持for-range的方式进行遍历,请注意两个细节
    (1)在遍历时,如果管道没有关闭,则会出现deadlock的错误
    (2)在遍历时,如果管道已经关闭,则会正常遍历数据,遍历完后,就会退出遍历。
package main

import (
	"fmt"
)

func main() {
	// 定义管道 、 声明管道
	var intChan chan int
	// 通过make初始化:管道可以存放3个int类型的数据
	intChan = make(chan int, 100)
	for i := 0; i < 100; i++ {
		intChan <- i
	}
	// 在遍历前,如果没有关闭管道,就会出现deadlock的错误
	// 所以我们在遍历前要进行管道的关闭
	close(intChan)
	// 遍历:for-range
	for v := range intChan {
		fmt.Println("value = ", v)
	}
}

12. 协程和管道协同工作的案例
13. 声明只读只写管道
14. 管道的阻塞
15. select功能
16. defer + recover机制处理错误
第13章:网络编程
第14章:反射

二、Golang进阶 - 网络通信

三、Golang进阶 - 并发编程

Go Web开发之前端技术实战

一、Go Web前置 - Go Module

二、Go Web前置 - HTML

三、Go Web前置-CSS

四、Go Web前置-JS

五、Go Web前置-JQuery

六、前端技术之Vue框架

GORM及数据库

一、GORM前置:MySQL

二、MySQL性能调优与架构设计

三、GORM

Go开发应用中间件

一、Redis_高效的NoSQL数据库

二、Redis缓存数据库进阶

三、Redis之go编程实战

四、消息中间件-Kafka实战

五、Kafka之go编程实战

六、RocketMQ基础实战版

七、NoSQL-MongoDB实战

八、分布式文件存储系统Minio

全文检索 ES

一、Elasticsearch核心知识篇

Go Web开发之企业级框架

一、Web框架

二、Gin深入实战

三、Beego框架开发实战

四、微服务架构

五、Go框架开发

六、Kong入门与实战

七、Logrus日志

企业级项目实战

相关文章:

  • ROS合集(一)ROS常见命令及其用途
  • springboot多种生产打包方式教程
  • 循环神经网络中用到的概率论知识
  • YOLOv8 OBB 旋转目标检测模型详解与实践
  • 59. 螺旋矩阵 II
  • 深度洞察:特种设备作业考试的核心要点与备考策略
  • 蓝桥杯 修剪灌木
  • opencv初步学习——图像处理3
  • LeetCode BFS层序遍历树
  • 工作记录 2017-02-04
  • 【css酷炫效果】纯CSS实现照片堆叠效果
  • 2025年通信安全员考试题库及答案
  • xxl-job 执行器端服务器的简单搭建
  • OneCyber 平台
  • 杨校老师课堂之编程入门与软件安装【图文笔记】
  • 将Django连接到mysql
  • numpy学习笔记8:数组属性和基础操作的详细描述
  • C++中pow函数的作用是什么,如何使用它?
  • Etcd 服务搭建
  • 【YOLOv8】YOLOv8改进系列(8)----替换主干网络之Swin Transformer
  • 霍步刚任辽宁沈阳市委书记
  • 国寿资产获批参与第三批保险资金长期投资改革试点
  • 韶关一企业将消防安装工程肢解发包,广东住建厅:罚款逾五万
  • 悬疑剧背后的女编剧:创作的差异不在性别,而在经验
  • 混乱的5天:俄乌和谈如何从充满希望走向“卡壳”
  • 浙江省台州市政协原副主席林虹被“双开”