可以边遍历边删除吗

2种情况:

  • 并发操作时:不可以。map在读的时候会检测写标志,如果发现一个协程在读的时候,另一个协程在写(包括删除和插入),则引发 fatal error: concurrent map iteration and map write
  • 单个routine:可以,但是不建议。因为遍历的结果中可能包含删除的 key,也可能不包含,这取决于删除 key 的时间:是在当前遍历 key 所在的 bucket 前还是后,可能会引发意外的逻辑错误。

并发读写(以插入和遍历为例)的场景我们测试一下:

package main  

import (  
   "fmt"  
   "strconv"
   "time"
)  

func main() {  
   m := make(map[int]string, 200)  

   go func() {  
      for {  
         for i := 0; i < 1000; i++ {  
            m[i] = strconv.Itoa(i)  
         }  
         time.Sleep(time.Microsecond)  
      }  
   }()  

   go func() {  
      for {  
         count := 0  
         for range m {  
            count++  
            time.Sleep(time.Microsecond)  
         }  
         fmt.Println("map count:", count)  
         time.Sleep(time.Second)  
      }  
   }()  

   time.Sleep(1 * time.Minute)  
}

执行:

fatal error: concurrent map iteration and map write

goroutine 35 [running]:
main.main.func2()
        15_go_syntax/maps/hash_map.go:30 +0xc7
created by main.main
        15_go_syntax/maps/hash_map.go:27 +0xaa

goroutine 1 [sleep]:
time.Sleep(0xdf8475800)
        /usr/local/Cellar/go/1.20.4/libexec/src/runtime/time.go:195 +0x135
main.main()
        15_go_syntax/maps/hash_map.go:39 +0xb9

goroutine 34 [runnable]:
main.main.func1()
        15_go_syntax/maps/hash_map.go:21 +0x7a
created by main.main
        15_go_syntax/maps/hash_map.go:18 +0x6d

附录——各语言map的对比: map-in-other-languages.png

Copyright © CoffeeChat 2020 all right reserved,powered by Gitbook该文件修订时间: 2023-05-31 16:34:35

results matching ""

    No results matching ""