当前位置:网站首页>Go语言学习教程(十五)
Go语言学习教程(十五)
2022-07-05 18:43:00 【小陈工】
一、线程休眠
* Go语言中main()函数为主线程(协程),程序是从上向下执行的
* 可以通过time包下的Sleep(n)让程序阻塞多少纳秒
//单位是纳秒,表示阻塞多长时间
//e9表示10的9次方
time.Sleep(1e9)
二、延迟执行
* 延迟指定时间后执行一次,但是需要注意在触发时程序没有结束
fmt.Println("开始")
//2秒后执行匿名函数
time.AfterFunc(2e9, func() {
fmt.Println("延迟延迟触发")
})
time.Sleep(10e9)//一定要休眠,否则程序结束了
fmt.Println("结束")
三、goroutine简介
* Golang中最迷人的一个优点就是从语言层面就支持并发
* 在Golang中的goroutine(协程)类似于其他语言的线程
* 并发和并行
* 并行(parallelism)指不同的代码片段同时在不同的物理处理器上支持
* 并发(concurrency)指同时管理多个事情,物理处理器上可能运行某个内容一半后就处理其他事情
* 在一般看来并发的性能要好于并行.因为计算机的物理资源是固定的,较少的,而程序需要执行的内容是很多的.所以并发是”以较少的资源去去做更多事情”
* 几种主流并发模型
* 多线程,每个线程只处理一个请求,只有请求结束后,对应的线程才会接收下一个请求.这种模式在高并发下,性能开销极大.
* 基于回调的异步IO.在程序运行过程中可能产生大量回调导致维护成本加大,程序执行流程也不便于思维
* 协程.不需要抢占式调用,可以有效提升线程任务的并发性,弥补了多线程模式的缺点;Golang在语言层面就支持,而其他语言很少支持
* goroutine的语法
* 表达式可以是一条语句
* 表达式也可以是函数,函数返回值即使有,也无效,当函数执行完成此goroutine自动结束
go 表达式
四、WaitGroup简介
* Golang中sync包提供了基本同步基元,如互斥锁等.除了Once和WaitGroup类型, 大部分都只适用于低水平程序线程,高水平同步线程使用channel通信更好一些
* WaitGroup直译为等待组,其实就是计数器,只要计数器中有内容将一直阻塞
* 在Golang中WaitGroup存在于sync包中,在sync包中类型都是不应该被拷贝的
* Go语言标准库中WaitGroup只有三个方法
* Add(delta int)表示向内部计数器添加增量(delta),其中参数delta可以是负数
* Done()表示减少WaitGroup计数器的值,应当在程序最后执行.相当于Add(-1)
* Wait()表示阻塞直到WaitGroup计数器为0
* 使用WaitGroup可以有效解决goroutine未执行完成而主协程执行完成,导致程序结束的goroutine未执行问题
var wg sync.WaitGroup
func main() {
for i := 1; i <= 3; i++ {
wg.Add(1)
go demo(i)
}
//阻塞,知道WaitGroup队列中所有任务执行结束时自动解除阻塞
fmt.Println("开始阻塞")
wg.Wait()
fmt.Println("任务执行结束,解除阻塞")
}
func demo(index int) {
for i := 1; i <= 5; i++ {
fmt.Printf("第%d次执行,i的值为:%d\n", index, i)
}
wg.Done()
}
五、互斥锁
* Go语言中多个协程操作一个变量时会出现冲突的问题
* go run -race 可以查看竞争
* 可以使用sync.Mutex对内容加锁
* 互斥锁的使用场景
* 多个goroutine访问同一个函数(代码段)
* 这个函数操作一个全局变量
* 为了保证共享变量安全性,值合法性
* 使用互斥锁模拟售票窗口
var (
//票数
num = 100
wg sync.WaitGroup
//互斥锁
mu sync.Mutex
)
func sellTicker(i int) {
defer wg.Done()
for {
//加锁,多个goroutine互斥
mu.Lock()
if num >= 1 {
fmt.Println("第", i, "个窗口卖了", num)
num = num - 1
}
//解锁
mu.Unlock()
if num <= 0 {
break
}
//添加休眠,防止结果可能出现在一个goroutine中
time.Sleep(time.Duration(rand.Int63n(1000) * 1e6))
}
}
func main() {
//设置随机数种子
rand.Seed(time.Now().UnixNano())
//计算器的起始值和票数相同
wg.Add(4)
go sellTicker(1)
go sellTicker(2)
go sellTicker(3)
go sellTicker(4)
wg.Wait()
fmt.Println("所有票卖完")
}
六、读写锁
* Go语言中的map不是线程安全的,多个goroutine同时操作会出现错误.
* RWMutex可以添加多个读锁或一个写锁.读写锁不能同时存在.
* map在并发下读写就需要结合读写锁完成
* 互斥锁表示锁的代码同一时间只能有一个goroutine运行,而读写锁表示在锁范围内数据的读写操作
func main() {
var rwm sync.RWMutex
m := make(map[string]string)
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func(j int) {
//没有锁在map时可能出现问题
rwm.Lock()
m["key"+strconv.Itoa(j)] = "value" + strconv.Itoa(j)
fmt.Println(m)
rwm.Unlock()
wg.Done()
}(i)
}
wg.Wait()
fmt.Println("程序结束")
}
一、channel
* 线程通信在每个编程语言中都是重难点,在Golang中提供了语言级别的goroutine之间通信:channel
* channel不同的翻译资料叫法不一样.常见的几种叫法
* 管道
* 信道
* 通道
* channel是进程内的通信方式,每个channel只能传递一个类型的值.这个类型需要在声明channel时指定
* channel在Golang中主要的两个作用
* 同步
* 通信
* Go语言中channel的关键字是chan
* 声明channel的语法
var 名称 chan 类型
var 名称 chan <- 类型 //只写
var 名称 <- chan 类型//只读
名称:=make(chan int) //无缓存channel
名称:=make(chan int,0)//无缓存channel
名称:=make(chan int,100)//有缓存channel
* 操作channel的语法:(假设定义一个channel名称为ch)
ch <- 值 //向ch中添加一个值
<- ch //从ch中取出一个值
a:=<-ch //从ch中取出一个值并赋值给a
a,b:=<-ch//从ch中取出一个值赋值给a,如果ch已经关闭或ch中没有值,b为false
* 简单无缓存通道代码示例
* 此代码中如果没有从channel中取值c,d=<-ch语句,程序结束时go func并没有执行
* 下面代码示例演示了同步操作,类似与WaitGroup功能,保证程序结束时goroutine已经执行完成
* 向goroutine中添加内容的代码会阻塞goroutine执行,所以要把ch<-1放入到goroutine有效代码最后一行
* 无论是向channel存数据还是取数据都会阻塞
* close(channel)关闭channel,关闭后只读不可写
func main() {
ch := make(chan int)
go func() {
fmt.Println("进入goroutine")
// 添加一个内容后控制台输出:1 true
//ch<-1
//关闭ch控制台输出:0 false
close(ch)
}()
c, d := <-ch
fmt.Println(c, d)
fmt.Println("程序执行结束")
}
* 使用channel实现goroutine之间通信
* channel其实就是消息通信机制实现方案,在Golang中没有使用共享内存完成线程通信,而是使用channel实现goroutine之间通信
func main() {
//用于goroutine之间传递数据
ch := make(chan string)
//用于控制程序执行
ch2 := make(chan string)
go func() {
fmt.Println("执行第一个goroutine,等待第二个goroutine传递数据")
content := <-ch
fmt.Println("接收到的数据为:", content)
ch2 <- "第一个"
}()
go func() {
fmt.Println("进入到第二个,开始传递数据")
ch <- "内容随意"
close(ch)
fmt.Println("发送数据完成")
ch2 <- "第二个"
}()
result1 := <-ch2
fmt.Println(result1, "执行完成")
result2 := <-ch2
fmt.Println(result2, "执行完成")
fmt.Println("程序执行结束")
}
* 可以使用for range获取channel中内容
* 不需要确定channel中数据个数
func main() {
ch:=make(chan string)
ch2:=make(chan int)
go func() {
for i:=97;i<97+26;i++{
ch <- strconv.Itoa(i)
}
ch2<-1
}()
go func() {
for c := range ch{
fmt.Println("取出来的",c)
}
}()
<-ch2
fmt.Println("程序结束")
}
* channel是安全的.多个goroutine同时操作时,同一时间只能有一个goroutine存取数据
func main() {
ch := make(chan int)
for i := 1; i < 5; i++ {
go func(j int) {
fmt.Println(j, "开始")
ch <- j
fmt.Println(j, "结束")
}(i)
}
for j := 1; j < 5; j++ {
time.Sleep(2 * time.Second)
<-ch
}
}
边栏推荐
- Emqx 5.0 officially released: a single cluster supports 100million mqtt connections
- cf:B. Almost Ternary Matrix【對稱 + 找規律 + 構造 + 我是構造垃圾】
- Blue sky drawing bed Apple quick instructions
- 5. Data access - entityframework integration
- EMQX 5.0 正式发布:单集群支持 1 亿 MQTT 连接
- 【历史上的今天】7 月 5 日:Google 之母出生;同一天诞生的两位图灵奖先驱
- 7-2 keep the linked list in order
- MySQL数据库索引教程(超详细)
- Applet modification style (placeholder, checkbox style)
- 如何快速进阶自动化测试?听听这3位BAT大厂测试工程师的切身感想....
猜你喜欢
The main thread anr exception is caused by too many binder development threads
Redhat7.4 configure Yum software warehouse (rhel7.4)
CF: B. almost Ternary Matrix [symétrie + règles de recherche + Construction + I am Construction Waste]
MYSQL中 find_in_set() 函数用法详解
AI金榜题名时,MLPerf榜单的份量究竟有多重?
[detailed explanation of AUTOSAR 14 startup process]
【历史上的今天】7 月 5 日:Google 之母出生;同一天诞生的两位图灵奖先驱
蚂蚁集团开源可信隐私计算框架「隐语」:开放、通用
面试官:Redis 过期删除策略和内存淘汰策略有什么区别?
Insufficient picture data? I made a free image enhancement software
随机推荐
Solutions contents have differences only in line separators
Interprocess communication (IPC): shared memory
技术分享 | 常见接口协议解析
EMQX 5.0 正式发布:单集群支持 1 亿 MQTT 连接
MySQL优化六个点的总结
Lombok @builder annotation
How to choose the most formal and safe external futures platform?
2022 latest intermediate and advanced Android interview questions, [principle + practice + Video + source code]
解决 contents have differences only in line separators
c期末复习
C language makes it easy to add, delete, modify and check the linked list "suggested collection"
进程间通信(IPC):共享内存
What is text mining? "Suggested collection"
Windows Oracle 开启远程连接 Windows Server Oracle 开启远程连接
集合处理的利器
Ant group open source trusted privacy computing framework "argot": open and universal
跨境支付平台 XTransfer 的低代码实践:如何与其他中台融合是核心
Why can't Bi software do correlation analysis? Take you to analyze
面试官:Redis 过期删除策略和内存淘汰策略有什么区别?
Startup and shutdown of CDB instances