Go语言 —— SelectMutex
Posted 之墨_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言 —— SelectMutex相关的知识,希望对你有一定的参考价值。
select
- select 语句用于在多个发送/接收信道操作中进行选择。
- select语句会一直阻塞,直到发送/接收操作准备就绪。
- 如果有多个信道操作准备完毕,select 会随机地选取其中之一执行。
示例
package main
import (
"fmt"
"time"
)
func server1(ch chan string) {
time.Sleep(6 * time.Second)
ch <- "from server1"
}
func server2(ch chan string) {
time.Sleep(3 * time.Second)
ch <- "from server2"
}
func main() {
output1 := make(chan string)
output2 := make(chan string)
go server1(output1)
go server2(output2)
select {
case s1 := <-output1:
fmt.Println(s1)
case s2 := <-output2:
fmt.Println(s2)
}
}
在上面程序里,
server1
函数(第 8 行)休眠了 6 秒,接着将文本from server1
写入信道ch
。而server2
函数(第 12 行)休眠了 3 秒,然后把from server2
写入了信道ch
。而
main
函数在第 20 行和第 21 行,分别调用了server1
和server2
两个 Go 协程。在第 22 行,程序运行到了
select
语句。select
会一直发生阻塞,除非其中有case
准备就绪。
在上述程序里,server1
协程会在 6 秒之后写入output1
信道,而server2
协程在 3 秒之后就写入了output2
信道。因此 select 语句会阻塞 3 秒钟,等着server2
向output2
信道写入数据。
Mutex
临界区
临界区(Critical Section):当程序并发地运行时,多个 Go 协程不应该同时访问那些修改共享资源的代码。这些修改共享资源的代码称为临界区。
例如,假设我们有一段代码,将一个变量 x 自增 1。
x = x + 1
- 如果只有一个 Go 协程访问上面的代码段,那是可行的。
但当有多个协程并发运行时,代码却会出错,让我们看看究竟是为什么吧。简单起见,假设在一行代码的前面,我们已经运行了两个 Go 协程。
- 在上一行代码的内部,系统执行程序时可以简单分为如下几个步骤:
- 获得 x 的当前值
- 计算 x + 1
- 将步骤 2 计算得到的值赋值给 x
如果只有一个协程执行上面的三个步骤,不会有问题。
如果在任意时刻只允许一个 Go 协程访问临界区,那么就可以避免竞态条件。而使用 Mutex 可以达到这个目的
- Mutex 用于提供一种加锁机制(Locking Mechanism),可确保在某时刻只有一个协程在临界区运行,以防止出现竞态条件。
- Mutex 可以在 sync 包内找到。Mutex 定义了两个方法:Lock 和 Unlock。所有在 Lock 和 Unlock 之间的代码,都只能由一个 Go 协程执行,于是就可以避免竞态条件。
- 这是一个使用Mutex解决竞态问题的例子
package main
import (
"fmt"
"sync"
)
var x = 0
func increment(wg *sync.WaitGroup, m *sync.Mutex) {
m.Lock()
x = x + 1
m.Unlock()
wg.Done()
}
func main() {
var w sync.WaitGroup
var m sync.Mutex
for i := 0; i < 1000; i++ {
w.Add(1)
go increment(&w, &m)
}
w.Wait()
fmt.Println("final value of x", x)
}
- 输出结果为
final value of x 1000
以上是关于Go语言 —— SelectMutex的主要内容,如果未能解决你的问题,请参考以下文章
windows通过Visual Studio Code中配置GO开发环境(转)
[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础
解决go: go.mod file not found in current directory or any parent directory; see ‘go help modules‘(代码片段