Go 之旅五: 并发
原文链接 http://ironxu.com/713 本文是学习 A Tour of Go (中文参考 Go 之旅中文 ) 整理的笔记。介绍Go 语言线程,信道以及互斥锁的概念和使用方法。 1. Go 线程
/** * go 语言线程 */
package main
import (
"fmt"
)
func say(s string) {
for i := 0; i < 2; i++ {
fmt.Println(i,s)
}
}
func main() {
go say("world")
say("hello")
}
Go 线程(goroutine)是由Go 运行时管理的轻量级线程。 go f(x,y,z)
会启动一个新的 Go 线程程并执行 f(x,z)
其中 Go 程在相同的地址空间中运行,因此在访问共享的内存时必须进行同步,这可以通过使用 2. 信道
/** * go 语言信道 */
package main
import "fmt"
func sum(s []int,c chan int) {
sum := 0
for _,v := range s {
sum += v
}
c <- sum
}
func fibonacci(n int,c chan int) {
x,y := 0, 1
for i := 0; i < n; i++ {
c <- x
x,y = y,x+y
}
close(c) // 关闭队列
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2],c)
go sum(s[len(s)/2:],c)
x,y := <-c,<-c // 从 c 中获取数据
fmt.Println(x,x+y)
// range 与 close
f := make(chan int, 10) // 创建带有缓冲区的管道
go fibonacci(cap(f),f)
for i := range f {
fmt.Println(i)
}
}
信道是带有类型的管道,通过信道操作符 ch <- v // 将 v 发送至信道 ch。
v := <-ch // 从 ch 接收值并赋予 v。
“箭头”就是数据流的方向。 信道在使用前必须创建: ch := make(chan int)
默认情况下,发送和接收操作在另一端准备好之前都会阻塞。这使得 Go 程可以在没有显式的锁或竞态变量的情况下进行同步。 2.1 带缓冲的信道信道可以是带缓冲的,将缓冲长度作为第二个参数提供给 make 来初始化一个带缓冲的信道: ch := make(chan int, 100)
仅当信道的缓冲区填满后,向其发送数据时才会阻塞。当缓冲区为空时,接受方会阻塞。 2.2 range 和 close发送者可通过 v,ok := <-ch
// ok == false
循环 注意: 只有发送者才能关闭信道,而接收者不能。向一个已经关闭的信道发送数据会引发程序错误。信道与文件不同,通常情况下无需关闭它们。只有在必须告诉接收者不再有值需要发送的时候才有必要关闭,如终止一个 3. select 语句
/** * go 语言 select */
package main
import (
"fmt"
)
// go 线程设置c 管道
func fibonacci(c,quit chan int) {
x, 1
for {
select {
case c<-x:
x,x+y
case <-quit:
fmt.Println("quit")
return
default:
fmt.Println(" .")
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
// go 线程读取c 管道
go func() {
for i:= 0; i < 5; i++{
fmt.Println(<-c)
}
quit<-0
}()
fibonacci(c,quit)
}
当 4. sync.Mutex
/** * go 互斥锁 */
package main
import (
"fmt"
"sync"
"time"
)
// 并发安全
type SafeCounter struct {
v map[string]int
mux sync.Mutex
}
// 增加计数器值
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
c.v[key]++
c.mux.Unlock()
}
// 返回当前计数器值
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
defer c.mux.Unlock() // 在Value 函数返回时解锁
return c.v[key]
}
func main() {
c := SafeCounter{v: make(map[string]int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}
time.Sleep(time.Second)
fmt.Println(c.Value("somekey")) //1000
}
互斥(mutual exclusion),指一次只有一个 Go 线程能够访问一个共享的变量。一般使用互斥锁(Mutex)来提供这种机制。 Go 标准库中提供了 Lock()
Unlock()
通过在代码前调用 参考
可以关注我的微博了解更多信息: @刚刚小码农 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |