通道
atomic和互斥锁都可以保证线程安全, 不过在go语言里, 还有一种有趣的实现就是通道
package main
import (
"fmt"
)
func main() {
buffered := make(chan string, 10)
buffered <- "hello world"
value := <-buffered
fmt.Println(value)
}
当一个资源需要在goroutine之间共享时, 通道在goroutine之间传递数据, 并且还提供了同步交换数据的机制.
在go语言中, 你需要使用 内置函数 make 来创建通道, 创建时需要指定数据类型
无缓冲的整数型通道
unbuffered := make ( chan int )
有缓冲的字符串通道
buffered := make ( chan string , 10 )
无缓冲通道
unbuffered channel 是指在接收前没有能力保存任何值的通道. 这种类型的通道要求发送方(goroutine) 和接收方(goroutine)同时准备好, 才能完成发送和接收操作.
如果两个goroutine没有同时准备好, 通道会导致先执行发送或者接收的goroutine阻塞等待. 这种对通道进行发送和接收的交互行为本身就是同步的.
其中任意一个操作都无法离开另一方操作独立存在
之前的例子里我们写过一个线程不安全的版本
package main
import (
"fmt"
"runtime"
"sync"
)
var (
count int32
wg sync.WaitGroup
)
func main() {
wg.Add(2)
go addValue()
go addValue()
wg.Wait()
fmt.Println(count)
}
func addValue() {
defer wg.Done()
for i := 0; i < 2; i++ {
value := count
runtime.Gosched()
value++
count = value
}
}
上面这段代码使用channel的线程安全版本是
package main
import (
"fmt"
"runtime"
"sync"
)
var (
count int32
channel chan int32
wg sync.WaitGroup
)
func main() {
runtime.GOMAXPROCS(2)
channel = make(chan int32, 10)
count = 0
channel <- count
wg.Add(2)
go addValue()
go addValue()
wg.Wait()
count = <-channel
fmt.Println(count)
}
func addValue() {
defer wg.Done()
for i := 0; i < 200; i++ {
value := <-channel
runtime.Gosched()
value++
channel <- value
}
}