被 Map 遍历打了脸
Map 遍历顺序是乱序的var convertJavaTimeFormat = map[string][string] {
"yyyy": "2006",
"yy": "06",
"MM": "01",
"dd": "02",
}
// ConvertTimeFormat formats t with java style format like yyyy-MM-dd.
func ConvertTimeFormat(t time.Time, javaStyleFmt string) string {
s := javaStyleFmt
for k, v := range convertJavaTimeFormat {
s = strings.ReplaceAll(s, k, v)
}
return t.Format(s)
}yyyyyyyyyyyyyyyy-MM-dd2021-06-082121-06-08When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next. If you require a stable iteration order you must maintain a separate data structure that specifies that order.
示例,playground,代码拷贝自这里
package main
import "fmt"
func main() {
blogArticleViews := map[string]int{
"unix": 0,
"python": 1,
"go": 2,
"javascript": 3,
"testing": 4,
"philosophy": 5,
"startups": 6,
"productivity": 7,
"hn": 8,
"reddit": 9,
"C++": 10,
}
for key, views := range blogArticleViews {
fmt.Println("There are", views, "views for", key)
}
}你猜想会出现下面这样吧:
There are 0 views for unix
There are 1 views for python
There are 2 views for go
There are 3 views for javascript
There are 4 views for testing
There are 5 views for philosophy
There are 6 views for startups
There are 7 views for productivity
There are 8 views for hn
There are 9 views for reddit
There are 10 views for C++
实际上呢,可能是这样的:
There are 3 views for javascript
There are 5 views for philosophy
There are 10 views for C++
There are 0 views for unix
There are 1 views for python
There are 2 views for go
There are 4 views for testing
There are 6 views for startups
There are 7 views for productivity
There are 8 views for hn
There are 9 views for reddit
改版如下:
var convertJavaTimeFormat = []string {
"yyyy", "2006",
"yy", "06",
"MM", "01",
"dd", "02",
}
// ConvertTimeFormat formats t with java style format like yyyy-MM-dd.
func ConvertTimeFormat(t time.Time, javaStyleFmt string) string {
s := javaStyleFmt
k := convertJavaTimeFormat
for i:=0; i+1 < len(k); i+=2 {
s = strings.ReplaceAll(s, k[i], k[i+1])
}
return t.Format(s)
}被切片切了一刀

package main
import (
"fmt"
)
func main() {
var a []byte
a = append(a, []byte(`012345678`)...)
fmt.Println(`len(a):`, len(a), `cap(a):`, cap(a))
fmt.Printf("a: %s, a's addr %p\n", a, &a[0])
b := append(a[:3], []byte(`...`)...)
fmt.Println(`len(b):`, len(b), `cap(b):`, cap(b))
fmt.Println(`len(a):`, len(a), `cap(a):`, cap(a))
fmt.Printf("a: %s, a's addr %p, b: %s, b's addr %p\n", a, &a[0], b, &b[0])
}输出结果
len(a): 9 cap(a): 16
a: 012345678, a's addr 0xc0000ae010
len(b): 6 cap(b): 16
len(a): 9 cap(a): 16
a: 012...678, a's addr 0xc0000ae010, b: 012..., b's addr 0xc0000ae010
被头等函数撞了一下头
package main
import (
"fmt"
"sync"
)
func cloneMap(src map[string]bool) map[string]bool {
dest := make(map[string]bool)
for k, v := range src {
dest[k] = v
}
return dest
}
func NewHandler() func(string) {
m := make(map[string]bool)
return func(v string) {
m = cloneMap(m)
m[v] = true
}
}
func main() {
var wg sync.WaitGroup
h := NewHandler()
for i := 0; i < 100; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
for j := 0; j < 10000; j++ {
h(fmt.Sprintf("Index:%d", index))
}
}(i)
}
wg.Wait()
}跑的结果是
fatal error: concurrent map iteration and map write
fatal error: concurrent map iteration and map write
也是不明所以,丈二和尚摸不着头脑,查了一会,才找到问题根源所在。
m := cloneMap(m)for select default 空转忙
httpdump 说线上 CPU 都 100% 以上,本地跑一下,果然如此,赶紧上 pprof,一查一个准
