fatal error: concurrent map writes
pioz opened this issue · 2 comments
pioz commented
I have a goroutine in a for loop that runs faker.FakeData
, here a sample code:
package main
import (
"reflect"
"github.com/bxcodec/faker"
)
type User struct {
Username string `faker:"first_name"`
Email string `faker:"email,unique"`
}
func main() {
user := User{}
modelType := reflect.TypeOf(user)
for i := 0; i < 1000; i++ {
go func() {
for j := 0; j < 1000; j++ {
modelCopy := reflect.New(modelType).Interface() // copy model
faker.FakeData(modelCopy)
}
}()
}
}
I get the follow error:
$ go run bin/faker.go
fatal error: concurrent map read and map write
goroutine 19 [running]:
runtime.throw(0x1122ca3, 0x21)
/usr/local/Cellar/go/1.14.1/libexec/src/runtime/panic.go:1114 +0x72 fp=0xc000221760 sp=0xc000221730 pc=0x1030a22
runtime.mapaccess1_faststr(0x10f41a0, 0xc00009a600, 0x10e3609, 0x5, 0x10eb480)
/usr/local/Cellar/go/1.14.1/libexec/src/runtime/map_faststr.go:21 +0x43c fp=0xc0002217d0 sp=0xc000221760 pc=0x10120fc
github.com/bxcodec/faker.getValue(0x10fb380, 0xc00020e580, 0x199, 0x10fb301, 0x10fb380, 0xc00020e580, 0xc00020e500)
/Users/pioz/Code/go/src/github.com/bxcodec/faker/faker.go:422 +0x1e2e fp=0xc000221b30 sp=0xc0002217d0 pc=0x10cbade
github.com/bxcodec/faker.getValue(0x10e58e0, 0xc00020e540, 0xc000221f48, 0x107ab78, 0x10fb380, 0xb7a0, 0x10e58e0)
/Users/pioz/Code/go/src/github.com/bxcodec/faker/faker.go:356 +0x174a fp=0xc000221e90 sp=0xc000221b30 pc=0x10cb3fa
github.com/bxcodec/faker.FakeData(0x10e58e0, 0xc00020e540, 0x16, 0xc00020e501)
/Users/pioz/Code/go/src/github.com/bxcodec/faker/faker.go:281 +0x1c6 fp=0xc000221f88 sp=0xc000221e90 pc=0x10c9896
main.main.func1(0x1145580, 0x10fb380)
/Users/pioz/Code/go/src/github.com/pioz/ct/bin/faker.go:23 +0x81 fp=0xc000221fd0 sp=0xc000221f88 pc=0x10da051
runtime.goexit()
/usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:1373 +0x1 fp=0xc000221fd8 sp=0xc000221fd0 pc=0x105d6a1
created by main.main
/Users/pioz/Code/go/src/github.com/pioz/ct/bin/faker.go:20 +0xaf
goroutine 1 [runnable]:
runtime.gopark(0x0, 0x0, 0xc000001008, 0x1)
/usr/local/Cellar/go/1.14.1/libexec/src/runtime/proc.go:287 +0x130
runtime.main()
/usr/local/Cellar/go/1.14.1/libexec/src/runtime/proc.go:222 +0x28c
runtime.goexit()
/usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:1373 +0x1
goroutine 20 [runnable]:
github.com/bxcodec/faker/support/slice.ContainsValue(0xc000226000, 0xaf, 0x100, 0x10eb480, 0xc00010d5b0, 0xc00010d5b0)
/Users/pioz/Code/go/src/github.com/bxcodec/faker/support/slice/helpers.go:21 +0x82
github.com/bxcodec/faker.getValue(0x10fb380, 0xc000115240, 0x199, 0x10fb301, 0x10fb380, 0xc000115240, 0xc0001151c0)
/Users/pioz/Code/go/src/github.com/bxcodec/faker/faker.go:422 +0x1e6b
github.com/bxcodec/faker.getValue(0x10e58e0, 0xc000115200, 0xc000195f48, 0x107ab78, 0x10fb380, 0xb7a0, 0x10e58e0)
/Users/pioz/Code/go/src/github.com/bxcodec/faker/faker.go:356 +0x174a
github.com/bxcodec/faker.FakeData(0x10e58e0, 0xc000115200, 0x16, 0xc000115201)
/Users/pioz/Code/go/src/github.com/bxcodec/faker/faker.go:281 +0x1c6
main.main.func1(0x1145580, 0x10fb380)
/Users/pioz/Code/go/src/github.com/pioz/ct/bin/faker.go:23 +0x81
created by main.main
/Users/pioz/Code/go/src/github.com/pioz/ct/bin/faker.go:20 +0xaf
...
If I remove the go
keyword all works fine.
If I remove the unique
option in the Email
field tag all works fine.
bxcodec commented
We haven't try to test this in a concurrent way.
My suggestion, I think you can add mutex on inside your goroutine.
mutex.Lock()
for j := 0; j < 1000; j++ {
faker.FakeData(modelCopy)
}
mutex.Unlock()
How about it?
pioz commented
This is the playground: https://play.golang.org/p/1T1aAsWgmhu
It would be nice if faker
managed concurrency internally.