2 回答

TA貢獻(xiàn)1828條經(jīng)驗(yàn) 獲得超3個(gè)贊
你有一些選擇:
使用
atomic.Value
:樣品 (1)使用
sync.RWMutex
:樣品 (3)使用
sync/atomic
:樣品 (6)僅使用通道和 goroutine:示例 (7)
另請(qǐng)參閱: 使用 sync.Mutex 還是通道?
1-您可以使用atomic.Value
:
值提供了一致類型值的原子加載和存儲(chǔ)。值可以作為其他數(shù)據(jù)結(jié)構(gòu)的一部分創(chuàng)建。Value 的零值從 Load 返回 nil。調(diào)用 Store 后,不得復(fù)制 Value。
首次使用后不得復(fù)制值。
像這個(gè)工作樣本:
// to test the panic use go build -race
package main
import (
"fmt"
"sync/atomic"
)
type test struct {
ch chan string
atomic.Value
}
func (t *test) run() {
for {
select {
case v := <-t.ch:
fmt.Printf("%+v, foo=%+v\n", v, t.Load())
t.Store(false)
default:
}
}
}
func (self *test) Ping() {
self.ch <- "ping"
}
func New() *test {
t := &test{
ch: make(chan string),
}
t.Store(false)
go t.run()
return t
}
func main() {
t := New()
for i := 0; i <= 10; i++ {
if x, _ := t.Load().(bool); x {
t.Ping()
}
// time.Sleep(time.Second)
if i%3 == 0 {
t.Store(true)
}
}
}
輸出go build -race:
ping, foo=true
ping, foo=false
ping, foo=false
ping, foo=false
ping, foo=false
2- 一點(diǎn)改進(jìn)func (t *test) run():
func (t *test) run() {
for v := range t.ch {
fmt.Printf("%+v, foo=%+v\n", v, t.Load())
t.Store(false)
}
}
3-您可以使用sync.RWMutexand sync.WaitGroup,就像這個(gè)工作示例一樣:
// to test the panic use go build -race
package main
import (
"fmt"
"sync"
)
type test struct {
ch chan string
foo bool
sync.RWMutex
sync.WaitGroup
}
func (t *test) run() {
for v := range t.ch {
t.Lock()
r := t.foo
t.foo = false
t.Unlock()
fmt.Printf("%+v, foo=%+v\n", v, r)
}
t.Done()
}
func (self *test) Ping() {
self.ch <- "ping"
}
func New() *test {
t := &test{ch: make(chan string)}
t.Add(1)
go t.run()
return t
}
func main() {
t := New()
for i := 0; i <= 10; i++ {
t.RLock()
r := t.foo
t.RUnlock()
if r {
t.Ping()
}
// time.Sleep(time.Second)
if i%3 == 0 {
t.Lock()
t.foo = true
t.Unlock()
}
}
close(t.ch)
t.Wait()
}
輸出go build -race:
ping, foo=true
ping, foo=true
ping, foo=false
ping, foo=true
ping, foo=false
ping, foo=true
4-所以讓我們按照這種方法https://talks.golang.org/2013/bestpractices.slide#29:
原始代碼:
package main
import (
"fmt"
"time"
)
type Server struct{ quit chan bool }
func NewServer() *Server {
s := &Server{make(chan bool)}
go s.run()
return s
}
func (s *Server) run() {
for {
select {
case <-s.quit:
fmt.Println("finishing task")
time.Sleep(time.Second)
fmt.Println("task done")
s.quit <- true
return
case <-time.After(time.Second):
fmt.Println("running task")
}
}
}
func (s *Server) Stop() {
fmt.Println("server stopping")
s.quit <- true
<-s.quit
fmt.Println("server stopped")
}
func main() {
s := NewServer()
time.Sleep(2 * time.Second)
s.Stop()
}
5-讓我們簡化它:
package main
import (
"fmt"
"time"
)
var quit = make(chan bool)
func main() {
go run()
time.Sleep(2 * time.Second)
fmt.Println("server stopping")
quit <- true // signal to quit
<-quit // wait for quit signal
fmt.Println("server stopped")
}
func run() {
for {
select {
case <-quit:
fmt.Println("finishing task")
time.Sleep(time.Second)
fmt.Println("task done")
quit <- true
return
case <-time.After(time.Second):
fmt.Println("running task")
}
}
}
輸出:
running task
running task
server stopping
finishing task
task done
server stopped
6-您的樣本的簡化版本:
// to test the panic use go build -race
package main
import "fmt"
import "sync/atomic"
var ch = make(chan string)
var state int32
func main() {
go run()
for i := 0; i <= 10; i++ {
if atomic.LoadInt32(&state) == 1 {
ch <- "ping"
}
if i%3 == 0 {
atomic.StoreInt32(&state, 1)
}
}
}
func run() {
for v := range ch {
fmt.Printf("%+v, state=%+v\n", v, atomic.LoadInt32(&state))
atomic.StoreInt32(&state, 0)
}
}
輸出:
ping, state=1
ping, state=0
ping, state=1
ping, state=0
ping, state=1
ping, state=0
7- 帶通道但不使用Lock()(The Go Playground)的工作樣本:
// to test the panic use go build -race
package main
import "fmt"
func main() {
go run()
for i := 0; i <= 10; i++ {
signal <- struct{}{}
if <-read {
ping <- "ping"
}
if i%3 == 0 {
write <- true
}
}
}
func run() {
foo := false
for {
select {
case <-signal:
fmt.Println("signal", foo)
read <- foo
case foo = <-write:
fmt.Println("write", foo)
case v := <-ping:
fmt.Println(v, foo)
foo = false
}
}
}
var (
ping = make(chan string)
signal = make(chan struct{})
read = make(chan bool)
write = make(chan bool)
)
輸出:
signal false
write true
signal true
ping true
signal false
signal false
write true
signal true
ping true
signal false
signal false
write true
signal true
ping true
signal false
signal false
write true
signal true
ping true

TA貢獻(xiàn)1876條經(jīng)驗(yàn) 獲得超7個(gè)贊
使用互斥鎖
package main
import (
"sync"
"time"
"fmt"
)
var myvar int
var mut sync.Mutex
func main() {
for {
go other()
go printer()
time.Sleep(time.Duration(1) * time.Second)
}
}
func other() {
mut.Lock()
myvar = myvar +1
mut.Unlock()
}
func printer() {
mut.Lock()
fmt.Println(myvar)
mut.Unlock()
}
運(yùn)行(使用互斥鎖)
$ go build -race t1.go
$ ./t1
1
2
3
4
5
6
7
7
9
10
運(yùn)行(沒有互斥體)
$ go build t2.go
$ go build -race t2.go
$ ./t2
==================
WARNING: DATA RACE
Read at 0x000000580ce8 by goroutine 7:
runtime.convT2E()
/usr/local/go/src/runtime/iface.go:155 +0x0
main.printer()
/.../.../.../GOPATH/t2.go:23 +0x65
Previous write at 0x000000580ce8 by goroutine 6:
main.other()
/.../.../.../GOPATH/t2.go:19 +0x3d
Goroutine 7 (running) created at:
main.main()
/.../.../.../GOPATH/t2.go:13 +0x5a
Goroutine 6 (finished) created at:
main.main()
/.../.../.../GOPATH/t2.go:12 +0x42
==================
1
2
- 2 回答
- 0 關(guān)注
- 168 瀏覽
添加回答
舉報(bào)