先单独说一下map,在Go语言中,map与通道类似,都需要先用make函数进行初始化,之后才可以赋值,不过map没有长度的限制,所以在使用make函数初始化map时,make函数的第二个参数不用写,写不写没有区别。
package main
import "fmt"
func main() {
var m map[int]int
//m = make(map[int]int,20)
m[22] = 10
fmt.Println(len(m))
}
运行结果
panic: assignment to entry in nil map
goroutine 1 [running]:
main.main()
错误原因,赋值给空map。
package main
import "fmt"
func main() {
var m map[int]int
m = make(map[int]int,20)
m[22] = 10
fmt.Println(len(m))
}
用make函数初始化map时,make的第二个参数写上也没有意义。
map在并发中
Go语言中map不是并发安全的,map不可以并发的写,但是可以并发的读。
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
m := make(map[int]int)
const N = 20
wg.Add(N)
for i := 0; i < N; i++ {
go func() {
defer wg.Done()
m[i] = i
}()
}
wg.Wait()
fmt.Println(len(m))
fmt.Println(m)
}
运行结果
fatal error: concurrent map writes
goroutine 7 [running]:
runtime.throw(0x10c4e4d, 0x15)
map在goroutine中并发写的时候不是线程安全的,所以不加锁会报错。
加锁后才可以并发写入
mu.Lock()
defer wg.Done()
m[i] = i
mu.Unlock()
不用加锁,可以并发读取
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
m := make(map[int]int)
const N = 20
for i := 0; i < N; i++ {
m[i] = i
}
wg.Add(N)
for i := 0; i < N; i++ {
go func(n int) {
fmt.Print(m[n],"\t")
wg.Done()
}(i)
}
wg.Wait()
fmt.Println("\n")
fmt.Println(m)
fmt.Println(len(m))
}
运行结果
19 6 7 8 9 10 11 12 13 14 15 16 17 18 5 3 4 0 2 1
map[6:6 10:10 11:11 15:15 17:17 1:1 2:2 4:4 7:7 8:8 16:16 0:0 3:3 9:9 19:19 5:5 12:12 13:13 14:14 18:18]
20