Golang并发编程入门教程
2021/12/26 11:08:59
本文主要是介绍Golang并发编程入门教程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
时间单位
- 1S = 1000ms
- 1ms = 1000us
- 1us = 1000ns
并发与并行
- 并行: 借助多核 cpu 实现。 (真 并行)
- 并发:
- 宏观:用户体验上,程序在并行执行。
- 微观:多个计划任务,顺序执行。在飞快的切换。轮换使用 cpu 时间轮片。 【假 并行】
进程并发
- 程序:编译成功得到的二进制文件。
- 占用磁盘空间
- 死的
- 系统中相同的程序一般只有一个,有可能存在不同版本号的程序
- 进程:运行起来程序。 占用系统资源。
- 进程是根据程序创建的,运行在内存中
- 活的
- 一个程序可以启动N个进程
- 一个程序可以启动N个进程,程序和进程的关系是1对N的关系。
进程状态
- 初始态
- 就绪态:程序会经常从就绪态切换到运行态。
- 运行态:只有运行态能切换到阻塞态。
- 挂起(阻塞)态:阻塞态可以切换回运行态继续往下执行。
- 终止(停止)态
线程并发
- 线程:LWP 轻量级的 进程。最小的执行单位。是cpu分配时间轮片的对象。
- 进程: 最小的系统资源分配单位。
同步
- 协同步调。规划先后顺序。
- 线程同步机制:
- 互斥锁(互斥量):建议锁。拿到锁以后,才能访问数据,没有拿到锁的线程,阻塞等待。等到拿锁的线程释放锁。
- 读写锁:一把锁(读属性、写属性)。 写独占,读共享。 写锁优先级高。
协程并发
- Python、Lua、Rust。。。
- 21世纪
- 线程会io阻塞,协程可以在线程io阻塞期间相互切换,执行其他不需要消耗io操作的协程
- 提高程序执行的效率
总结
- 进程、线程、协程 都可以完成并发。
- 稳定性强、节省资源、效率高。
- 老板——手机:
- 生产线 —— 设备、材料、厂房 —— 进程。(资源分配单位)
- 工人 —— 线程。 —— 单进程、单线程的 程序。
- 50 工人 —— 50 线程。 ——单进程、多线程的 程序。
- 10 条生产线 —— 500 工人 —— 。多进程、多线程的 程序。
- 利用闲暇时间义务搬砖 —— 协程。—— 多进程、多线程、多协程 程序。
创建Goroutine程
- 创建于进程中。 直接使用 go 关键,放置于 函数调用前面,产生一个 go程。 并发。
示例代码:
package main import ( "fmt" `time` ) // 唱歌 func sing() { for i:=0;i<50;i++ { fmt.Println("----正在唱:隔壁泰山----") } } // 跳舞 func dance() { for i:=0;i<50;i++ { fmt.Println("----正在跳舞:赵四街舞----") } } func main() { go sing() // 开启goroutine go dance() // 另一个goroutine,会抢夺CPU执行权,两个goroutine交替执行 time.Sleep(time.Second) }
Goroutine的特性:【重点】
- 主go程结束,子go程随之退出。
示例代码:
package main import ( "fmt" "time" ) func main() { go func() { // 创建一个 子go 程 for i := 0; i < 5; i++ { fmt.Println("------I'm goroutine -------") time.Sleep(time.Second) } }() // 主goroutine结束,子goroutine随着退出 // 所以,子goroutine很有可能没有执行完就退出了 fmt.Println("------I'm main-------") }
runtime.Gosched()
- 出让当前go程所占用的 cpu时间片。当再次获得cpu时,从出让位置继续回复执行。
- 时间片轮转调度算法。
示例代码:
package main import ( "fmt" "runtime" ) func main() { go func() { for { runtime.Gosched() fmt.Println("goroutine 1执行。。。。") } }() for { runtime.Gosched() // 出让当前 cpu 时间片。 fmt.Println("主go程执行。。。。") } }
runtime.Goexit()
- return: 返回当前函数调用到调用者那里去。 return之前的 defer 注册生效。
- Goexit(): 结束调用该函数的当前go程。Goexit():之前注册的 defer都生效。
示例代码:
package main import ( "fmt" "runtime" `time` ) func test() { defer fmt.Println("退出子go程之前") // return runtime.Goexit() // 退出当前go程。 defer fmt.Println("退出子go程之后") } func main() { fmt.Println("主go程开始执行") go func() { fmt.Println("父go程执行之前") // runtime.Goexit() 会确保defer执行 defer fmt.Println("defer 父go程执行之后") go test() fmt.Println("父go程执行之后") }() fmt.Println("主go程结束执行") time.Sleep(time.Second) }
runtime.GOMAXPROCS()
- 设置当前 进程使用的最大cpu核数。 返回 上一次调用成功的设置值。 首次调用返回默认值。
示例代码:
package main import ( "fmt" "runtime" ) func main() { fmt.Println(runtime.GOROOT()) n := runtime.GOMAXPROCS(0) // 0表示最大 fmt.Println("n = ", n) // 返回上次设置成功的设置值 n = runtime.GOMAXPROCS(2) fmt.Println("n = ", n) // 16 n = runtime.GOMAXPROCS(4) fmt.Println("n = ", n) // 2 n = runtime.GOMAXPROCS(8) fmt.Println("n = ", n) // 4 n = runtime.GOMAXPROCS(1) fmt.Println("n = ", n) // 8 }
补充知识点
- 每当有一个进程启动时,系统会自动打开三个文件: 标准输入、标准输出、标准错误。 —— 对应三个文件: stdin、stdout、stderr
- 当进行运行结束。操作系统自动关闭三个文件。
channel
- 是一种数据类型。 对应一个“管道”(通道 FIFO)
- channel的定义:
- make (chan 在channel中传递的数据类型, 容量)
- 容量= 0: 无缓冲channel
- 容量 > 0 :有缓冲channel
- make(chan int) 或 make (chan string , 0)
- make (chan 在channel中传递的数据类型, 容量)
- channel有两个端:
- 一端:写端(传入端) chan <-
- 另一端: 读端(传出端)<- chan
- 要求:读端和写端必须同时满足条件,才在shan上进行数据流动。否则,则阻塞。
- channel是一种先进先出(FIFO)的队列类型
示例代码
package main import ( "fmt" "time" ) // 全局定义channel, 用来完成数据同步 var flagChan = make(chan struct{}) // 空struct不占用空间 // 定义一台打印机 func printer(s string) { for _, ch := range s { fmt.Printf("%c", ch) // 屏幕:stdout time.Sleep(300 * time.Millisecond) } } // 定义两个人使用打印机 func person1() { // person 先执行。 printer("hello") flagChan <- struct{}{} // 写入数据,解除阻塞 } func person2() { // person 后执行 printer("world") flagChan <- struct{}{} // 写入数据,解除阻塞 } func main() { go person1() <-flagChan // 拿到数据之前,一直阻塞,所以会等到go程执行结束,直到写入 go person2() <- flagChan fmt.Println("\n程序执行结束!!!") }
这篇关于Golang并发编程入门教程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-24MongoDB资料:新手入门完全指南
- 2024-12-20go-zero 框架的 RPC 服务 启动start和停止 底层是怎么实现的?-icode9专业技术文章分享
- 2024-12-19Go-Zero 框架的 RPC 服务启动和停止的基本机制和过程是怎么实现的?-icode9专业技术文章分享
- 2024-12-18怎么在golang中使用gRPC测试mock数据?-icode9专业技术文章分享
- 2024-12-15掌握PageRank算法核心!你离Google优化高手只差一步!
- 2024-12-15GORM 中的标签 gorm:"index"是什么?-icode9专业技术文章分享
- 2024-12-11怎么在 Go 语言中获取 Open vSwitch (OVS) 的桥接信息(Bridge)?-icode9专业技术文章分享
- 2024-12-11怎么用Go 语言的库来与 Open vSwitch 进行交互?-icode9专业技术文章分享
- 2024-12-11怎么在 go-zero 项目中发送阿里云短信?-icode9专业技术文章分享
- 2024-12-11怎么使用阿里云 Go SDK (alibaba-cloud-sdk-go) 发送短信?-icode9专业技术文章分享