-
(1) goroutine是一个被Go运行时管理的轻量级线程
go f(x, y, z)f, x, y, and z在当前goroutine发生,f函数的执行在新的goroutine发生
(2) Goroutine在同一块地址空间运行,所以共享内存时需要同步
-
channels
(1) Channels是一种__管道__,可以通过channels来发送和接收变量值,使用 __<-__运算符
ch <- v // Send v to channel ch v := <-ch // Receive from ch, and assign value to v(2) 和map和slice一样,channel也需要先声明
ch := make(chan int) //channel sl := make([]int, 5) //slice m := make(map[string]int) //map(3) 在经由channel发送或接收时,必须另一方准备好以后才开始发送/接收,否则就会Block
这提供了__同步__的一种方法
package main import "fmt" func sum(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum // send sum to 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 // receive from c fmt.Println(x, y, x+y) }(4) 带__buffer__的channel
在创建时指定buffer数量
ch := make(chan int, 2)当buffer已满时,会阻塞发送方;当buffer已空时,会阻塞取回方。如果只有一个线程会被报死锁错误
package main import "fmt" func main() { ch := make(chan int, 2) ch <- 1 ch <- 2 fmt.Println(<-ch) fmt.Println(<-ch) }(5) 用
v, ok := <-ch可以判断channel是否关闭
(6) 用
for i := range c可以反复从channel获取值,直到channel关闭
(7) 只有发送方可以关闭channel
close(c)但是事实上关闭channel的操作不是必须的(和关闭文件不一样),只有提示接收方终止循环时关闭channel才有必要
package main import ( "fmt" ) 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() { c := make(chan int, 10) go fibonacci(cap(c), c) for i := range c { fmt.Println(i) } } -
select语句
(1) select阻塞直到select块中的某个case可以运行。如果多个case都可以运行,那就随机选一个
package main import "fmt" func fibonacci(c, quit chan int) { x, y := 0, 1 for { select { case c <- x: x, y = y, x+y case <-quit: fmt.Println("quit") return } } } func main() { c := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { fmt.Println(<-c) } quit <- 0 }() fibonacci(c, quit) }(2) 如果select块中有default,那么当其他的case都不是ready状态时,执行default块中的内容
package main import ( "fmt" "time" ) func main() { tick := time.Tick(100 * time.Millisecond) boom := time.After(500 * time.Millisecond) for { select { case <-tick: fmt.Println("tick.") case <-boom: fmt.Println("BOOM!") return default: fmt.Println(" .") time.Sleep(50 * time.Millisecond) } } } -
sync.Mutex
(1) 当我们只需要确保互斥访问变量值,不需要用channel沟通时,可以考虑使用sync.Mutex
(2) sync.Mutex有两个方法
Lock Unlock有一个小技巧是使用__defer__确保unlock()操作一定执行
package main import ( "fmt" "sync" "time" ) // SafeCounter is safe to use concurrently. type SafeCounter struct { v map[string]int mux sync.Mutex } // Inc increments the counter for the given key. func (c *SafeCounter) Inc(key string) { c.mux.Lock() // Lock so only one goroutine at a time can access the map c.v. c.v[key]++ c.mux.Unlock() } // Value returns the current value of the counter for the given key. func (c *SafeCounter) Value(key string) int { c.mux.Lock() // Lock so only one goroutine at a time can access the map c.v. defer c.mux.Unlock() //这里用defer很巧妙 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")) }
5_Concurrency
最新推荐文章于 2023-09-16 18:52:00 发布
本文介绍了Go语言的并发特性。goroutine是轻量级线程,在同一块地址空间运行,共享内存需同步。Channels是管道,用于发送和接收变量值,有同步作用,还有带buffer的channel。select语句可阻塞直到某个case可运行。sync.Mutex可确保互斥访问变量值。
2676

被折叠的 条评论
为什么被折叠?



