处理切片并发时,如果没有使用互斥锁,结果可能不如预期。

huangapple go评论82阅读模式
英文:

Dealing with slices concurrently is not working as expected without mutexes

问题

WithMutexWithoutMutex函数给出了不同的结果。

尽管我设置了Waitgroup,但WithoutMutex的实现丢失了值。

可能出了什么问题?

请勿在Playground上运行

P.S. 我使用的是Windows 10和Go 1.8.1

package main

import (
	"fmt"
	"sync"
)

var p = fmt.Println

type MuType struct {
	list []int
	*sync.RWMutex
}

var muData *MuType
var data *NonMuType

type NonMuType struct {
	list []int
}

func (data *MuType) add(i int, wg *sync.WaitGroup) {
	data.Lock()
	defer data.Unlock()
	data.list = append(data.list, i)
	wg.Done()

}

func (data *MuType) read() []int {
	data.RLock()
	defer data.RUnlock()
	return data.list
}

func (nonmu *NonMuType) add(i int, wg *sync.WaitGroup) {
	nonmu.list = append(nonmu.list, i)
	wg.Done()

}

func (nonmu *NonMuType) read() []int {
	return nonmu.list
}

func WithoutMutex() {
	nonmu := &NonMuType{}
	nonmu.list = make([]int, 0)
	var wg = sync.WaitGroup{}
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go nonmu.add(i, &wg)

	}
	wg.Wait()
	data = nonmu
	p(data.read())
}

func WithMutex() {
	mtx := &sync.RWMutex{}
	withMu := &MuType{list: make([]int, 0)}
	withMu.RWMutex = mtx
	var wg = sync.WaitGroup{}
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go withMu.add(i, &wg)
	}
	wg.Wait()
	muData = withMu
	p(muData.read())
}

func stressTestWOMU(max int) {
	p("Without Mutex")
	for ii := 0; ii < max; ii++ {
		WithoutMutex()
	}
}

func stressTest(max int) {
	p("With Mutex")
	for ii := 0; ii < max; ii++ {
		WithMutex()
	}
}

func main() {
	stressTestWOMU(20)
	stressTest(20)
}
英文:

Functions WithMutex and WithoutMutex are giving different results.

WithoutMutex implementation is losing values even though I have Waitgroup set up.

What could be wrong?

Do not run on Playground

P.S. I am on Windows 10 and Go 1.8.1

package main
import (
&quot;fmt&quot;
&quot;sync&quot;
)
var p = fmt.Println
type MuType struct {
list []int
*sync.RWMutex
}
var muData *MuType
var data *NonMuType
type NonMuType struct {
list []int
}
func (data *MuType) add(i int, wg *sync.WaitGroup) {
data.Lock()
defer data.Unlock()
data.list = append(data.list, i)
wg.Done()
}
func (data *MuType) read() []int {
data.RLock()
defer data.RUnlock()
return data.list
}
func (nonmu *NonMuType) add(i int, wg *sync.WaitGroup) {
nonmu.list = append(nonmu.list, i)
wg.Done()
}
func (nonmu *NonMuType) read() []int {
return nonmu.list
}
func WithoutMutex() {
nonmu := &amp;NonMuType{}
nonmu.list = make([]int, 0)
var wg = sync.WaitGroup{}
for i := 0; i &lt; 10; i++ {
wg.Add(1)
go nonmu.add(i, &amp;wg)
}
wg.Wait()
data = nonmu
p(data.read())
}
func WithMutex() {
mtx := &amp;sync.RWMutex{}
withMu := &amp;MuType{list: make([]int, 0)}
withMu.RWMutex = mtx
var wg = sync.WaitGroup{}
for i := 0; i &lt; 10; i++ {
wg.Add(1)
go withMu.add(i, &amp;wg)
}
wg.Wait()
muData = withMu
p(muData.read())
}
func stressTestWOMU(max int) {
p(&quot;Without Mutex&quot;)
for ii := 0; ii &lt; max; ii++ {
WithoutMutex()
}
}
func stressTest(max int) {
p(&quot;With Mutex&quot;)
for ii := 0; ii &lt; max; ii++ {
WithMutex()
}
}
func main() {
stressTestWOMU(20)
stressTest(20)
}

答案1

得分: 1

切片在并发写入时不安全,所以我对WithoutMutex不一致且丢失元素的情况一点也不感到惊讶。

WithMutex版本始终有10个元素,但顺序混乱。这也是可以预料的,因为互斥锁保护它,只有一个goroutine可以进行追加操作。但是,无法保证哪个goroutine会以哪种顺序运行,因此快速生成的goroutine之间会竞争,看哪个会先进行追加操作。

等待组不会控制访问或强制排序。它只是在最后提供一个信号,表示所有操作都已完成。

英文:

Slices are not safe for concurrent writes, so I am in no way surprised that WithoutMutex does not appear to be consistent at all, and has dropped items.

The WithMutex version consistently has 10 items, but in jumbled orders. This is also to be expected, since the mutex protects it so that only one can append at a time. There is no guarantee as to which goroutine will run in which order though, so it is a race to see which of the rapidly spawned goroutines will get to append first.

The waitgroup does not do anything to control access or enforce ordering. It merely provides a signal at the end that everything is done.

huangapple
  • 本文由 发表于 2017年5月5日 16:00:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/43799555.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定