package foundation import ( "fmt" "strconv" "sync" "time" ) /* map 未初始化时,默认是是nil,无法直接赋值,需要先用make初始化 1. testMapInit() map 测试被赋值后的地址变化 1. testAssign() * map整体被赋值后,内存地址更新为新map的地址 map不是协程安全,会出现并发读写问题 1. 并发读 testReadSync() succeed 可以 2. 并发写 testWriteSync() failed 报错 3. 并发读写 testRWSync() failed 报错 4. 并发写+len() testWLenSync() succeed 可以 (任何情况下,len()操作并发安全) 5. 并发读+ rebuild testReadRebuild() succeed (读 + rebuild是不会存在并发安全问题的) 6. 并发写 + rebuild testWriteRebuild() succees (写 + rebuild也没偶并发报错,但是可能会造成写数据不生效,有逻辑异常) map测试读写锁RWMutex(共享锁) 1. Lock/Unlock 写锁定/解锁,写的时候什么也不能干 * Lock/Unlock是互斥锁,好像和sync.Mutex中的Lock/UnLock没有区别 * testLockRead() 测试了Mutex中Lock/UnLock的互斥性 * 发现1、2、3均按顺序进入和退出 2. RLock/RUnlock 读锁定/读解锁,可以同时读,但读的同时不能写 * testRLockRead() 发现1、2、3同时进入start,表示读可以共享 3. 使用map测试 * testRWWithLock() */ var ( c = make(map[string]int64) ) func mapRead() { var i int64 for ; i < 10000; i++ { _ = c[strconv.FormatInt(i, 10)] } fmt.Println("read exit") } func mapWrite() { var i int64 for ; i < 10000; i++ { c[strconv.FormatInt(i, 10)] = i } fmt.Println("write exit") } func mapRebuild() { var i int64 for ; i < 10000; i++ { a := make(map[string]int64) c = a } fmt.Println("rebuild exit") } func mapLen() { var i int64 for ; i < 10000; i++ { _ = len(c) } } // 并发读测试 func testReadSync() { go mapRead() go mapRead() time.Sleep(time.Second) } // 并发写测试 func testWriteSync() { go mapWrite() go mapWrite() time.Sleep(time.Second) } // 并发读写测试 func testRWSync() { go mapRead() go mapWrite() time.Sleep(time.Second) } // 并发写 + len func testWLenSync() { go mapWrite() go mapLen() time.Sleep(time.Second) } // 并发读 + rebuild func testReadRebuild() { go mapRead() go mapRebuild() time.Sleep(time.Second) fmt.Println("testReadRebuild exit") } // 并发写 + rebuild func testWriteRebuild() { go mapWrite() go mapRebuild() time.Sleep(time.Second) fmt.Println("testWriteRebuild exit") } var lock = new(sync.Mutex) var rwlock = new(sync.RWMutex) // 加互斥锁 读 func LockRead(i int64) { lock.Lock() defer lock.Unlock() fmt.Println("read start", i) time.Sleep(1 * time.Second) fmt.Println("reading", i) fmt.Println("read done", i) } // 加共享锁 读 read无序,读可共享 func RLockRead(i int64) { rwlock.RLock() defer rwlock.RUnlock() fmt.Println("read start", i) time.Sleep(1 * time.Second) fmt.Println("reading", i) fmt.Println("read done", i) } func testLockRead() { go LockRead(1) go LockRead(2) go LockRead(3) time.Sleep(5 * time.Second) } func testRLockRead() { go RLockRead(1) go RLockRead(2) go RLockRead(3) time.Sleep(5 * time.Second) } // map 加读锁read func mapRLockRead() { var i int64 for ; i < 10000; i++ { rwlock.RLock() fmt.Println("read", i) _ = c[strconv.FormatInt(i, 10)] rwlock.RUnlock() } } // map 加互斥锁write func mapLockWrite() { var i int64 for ; i < 10000; i++ { rwlock.Lock() fmt.Println("write", i) c[strconv.FormatInt(i, 10)] = i rwlock.Unlock() } } func testRWWithLock() { go mapRLockRead() go mapRLockRead() go mapLockWrite() time.Sleep(time.Second) } // 测试map 被赋值后的内存地址变化 func testAssign() { a := map[string]int64{"a": 1} fmt.Println(a, &a) fmt.Printf("%p\n", &a) b := map[string]int64{"b": 1} fmt.Println(b, &b) fmt.Printf("%p\n", &b) a = b fmt.Println(a, &a) fmt.Printf("%p\n", &a) } func testMapInit() { // 方式一:先声明,在初始化 var mapA map[int64]string // 仅声明map时,其默认值是nil,不能直接赋值,需要make初始化 // mapA[12] = "test" // panic: assignment to entry in nil map mapA = make(map[int64]string) mapA[12] = "test" fmt.Println(mapA) // 方式二:直接初始化赋值 mapB := make(map[int64]string) mapB[12] = "test1" fmt.Println(mapB) // 方式三:声明 + 初始化 var mapC map[int64]string = map[int64]string{12: "test2", 13: "test3"} fmt.Println(mapC) } func TestMap() { // testWriteSync() // fatal error: concurrent map writes // testReadSync() // success // testRWSync() // fatal error: concurrent map read and map write // testReadRebuild() // success // testWriteRebuild() // success // testLockRead() // 1、2、3依次start/reading/done // testRLockRead() // 1、2、3同时进入start // testRWWithLock() // 加锁后读写无error,但是不能体现读锁的特性 // testWLenSync() // len() 操作和write无并发错误 // testAssign() // testMapInit() }