在过去的几周里,我一直在努力解决一个(不太)简单的问题:
sync.Mutex
,相反,什么时候最好使用 chan
?对于很多问题来说,两种策略似乎都可以互换 - 这就是问题所在!
观看 Golang 文档中的 此视频。
下面,我冒昧地在操场上指定了代码,并将其翻译为
sync.Mutex
等效项。
备注:
chan
用法的超级粉丝,并且很难想出使用 sync.Mutex
的更优雅的实现。chan
实现同时做了更多的工作(达到12)*游乐场:
用
chan
进行乒乓/乒乓球:
package main
import (
"fmt"
"time"
)
type Ball struct { hits int }
func main() {
table := make(chan *Ball)
go player("ping", table)
go player("pong", table)
table <- new(Ball)
time.Sleep(1 * time.Second)
<-table
}
func player(name string, table chan *Ball) {
for {
ball := <-table
ball.hits++
fmt.Println(name, ball.hits)
time.Sleep(100 * time.Millisecond)
table <- ball
}
}
用
sync.Mutex
进行乒乓/乒乓球:
package main
import (
"fmt"
"time"
"sync"
)
type Ball struct { hits int }
var m = sync.Mutex{}
func main() {
ball := new(Ball)
go player("ping", ball)
go player("pong", ball)
time.Sleep(1 * time.Second)
}
func player(name string, ball *Ball) {
for {
m.Lock()
ball.hits++
fmt.Println(name, ball.hits)
time.Sleep(100 * time.Millisecond)
m.Unlock()
}
}
在 Go 中,通道非常棒,你可以使用它们在 goroutine 之间进行通信。但是,为了方便起见,在某些情况下您可能需要使用
sync.Mutex
。
这些情况如下:
这里有三个示例和解释
一些渠道用例示例:
一些示例原语用例:
sync.Mutex
或sync.RWMutex
)为了说清楚,假设我们需要一个一秒计数器,因此在下面的示例中,我们计数一秒,然后打印计数器值以查看其计数速度:
No | Count | Method
------------------------------------------------------
1 | 17_729_027 | Using sync.RWMutex for increment
2 | 12_180_741 | Using channel for increment
3 | 106_743_095 | Using channel for timer
4 | 104_178_671 | Using time.AfterFunc and channel sync
注意:go版本go1.13.5 linux/amd64
代码:
1 - 使用
sync.RWMutex
进行增量:
package main
import (
"sync"
"time"
)
func main() {
var i rwm
go func() {
for {
i.inc() // free running counter
}
}()
time.Sleep(1 * time.Second)
println(i.read()) // sampling the counter
}
type rwm struct {
sync.RWMutex
i int
}
func (l *rwm) inc() {
l.Lock()
defer l.Unlock()
l.i++
}
func (l *rwm) read() int {
l.RLock()
defer l.RUnlock()
return l.i
}
2 - 使用通道进行增量:
package main
import (
"time"
)
func main() {
ch := make(chan int, 1)
ch <- 1
timeout := time.NewTimer(1 * time.Second)
loop:
for {
select {
case <-timeout.C:
timeout.Stop()
break loop
default:
ch <- 1 + <-ch
}
}
println(<-ch)
}
3 - 使用定时器通道:
package main
import "time"
func main() {
ch := make(chan int)
go func() {
timeout := time.NewTimer(1 * time.Second)
defer timeout.Stop()
i := 1
for {
select {
case <-timeout.C:
ch <- i
return
default:
i++
}
}
}()
println(<-ch)
}
4 - 使用
time.AfterFunc
和通道同步:
package main
import (
"fmt"
"time"
)
func main() {
d := 1 * time.Second
i := uint64(0)
ch := make(chan struct{})
time.AfterFunc(d, func() {
close(ch)
})
loop:
for {
select {
case <-ch:
break loop
default:
i++
}
}
fmt.Println(i) // 104_178_671
}