在过去的几周里,我一直在努力解决一个(不太)简单的问题:
sync.Mutex,反之,什么时候最好使用 a 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
}
}
Run Code Online (Sandbox Code Playgroud)
乒乓球/乒乓球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()
}
}
Run Code Online (Sandbox Code Playgroud)
一些渠道用例示例:
一些示例原语用例:
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
Run Code Online (Sandbox Code Playgroud)
注: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
}
Run Code Online (Sandbox Code Playgroud)
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)
}
Run Code Online (Sandbox Code Playgroud)
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)
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)