Go语言 —— Select、Mutex

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 行,分别调用了 server1server2 两个 Go 协程。

在第 22 行,程序运行到了 select 语句。select 会一直发生阻塞,除非其中有 case
准备就绪。
在上述程序里,server1 协程会在 6 秒之后写入 output1 信道,而server2 协程在 3 秒之后就写入了 output2 信道。因此 select 语句会阻塞 3 秒钟,等着 server2output2
信道写入数据。

Mutex

临界区

临界区(Critical Section):当程序并发地运行时,多个 Go 协程不应该同时访问那些修改共享资源的代码。这些修改共享资源的代码称为临界区。

例如,假设我们有一段代码,将一个变量 x 自增 1。

x = x + 1
  • 如果只有一个 Go 协程访问上面的代码段,那是可行的。

但当有多个协程并发运行时,代码却会出错,让我们看看究竟是为什么吧。简单起见,假设在一行代码的前面,我们已经运行了两个 Go 协程。

  • 在上一行代码的内部,系统执行程序时可以简单分为如下几个步骤
  1. 获得 x 的当前值
  2. 计算 x + 1
  3. 将步骤 2 计算得到的值赋值给 x

如果只有一个协程执行上面的三个步骤,不会有问题。
如果在任意时刻只允许一个 Go 协程访问临界区,那么就可以避免竞态条件。而使用 Mutex 可以达到这个目的

  1. Mutex 用于提供一种加锁机制(Locking Mechanism),可确保在某时刻只有一个协程在临界区运行,以防止出现竞态条件。
  2. 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语言)