funcmain() { var ch chanint var count int gofunc() { ch <- 1 }() gofunc() { count++ close(ch) }() <-ch fmt.Println(count) }
ch只声明,未进行初始化,所以panic:
1 2 3 4 5 6 7 8
panic: close of nil channel
goroutine 34 [running]: main.main.func2(0xc000096000, 0x0) /Users/shitaibin/Workspace/golang_step_by_step/problems/concurrent/channel1.go:13 +0x33 created by main.main /Users/shitaibin/Workspace/golang_step_by_step/problems/concurrent/channel1.go:11 +0x87 exit status 2
修改为下面这样,还有问题吗?:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
package main
import"fmt"
funcmain() { // var ch chan int ch := make(chanint) var count int gofunc() { ch <- 1 }() gofunc() { count++ close(ch) }() <-ch fmt.Println(count) }
同样会panic,典型的channel由非发送者关闭,造成在关闭的channel上写数据。
1 2 3 4 5 6 7 8 9
1 panic: send on closed channel
goroutine 4 [running]: main.main.func1(0xc000070060) /Users/shitaibin/Workspace/golang_step_by_step/problems/concurrent/channel1.go:10 +0x37 created by main.main /Users/shitaibin/Workspace/golang_step_by_step/problems/concurrent/channel1.go:9 +0x80 exit status 2
Map 1
1 2 3 4 5 6 7 8 9 10 11 12 13
package main
import ( "fmt" "sync" )
funcmain() { var m sync.Map m.LoadOrStore("a", 1) m.Delete("a") fmt.Println(m.Len()) }
func(m *Map)Get(key int)(int, bool) { m.Lock() defer m.Unlock() i, ok := m.m[key] return i, ok }
func(m *Map)Put(key, value int) { m.Lock() defer m.Unlock() m.m[key] = value }
func(m *Map)Len()int { returnlen(m.m) }
funcmain() { var wg sync.WaitGroup wg.Add(2) m := Map{m: make(map[int]int)} gofunc() { for i := 0; i < 10000000; i++ { m.Put(i, i) } wg.Done() }() gofunc() { for i := 0; i < 10000000; i++ { m.Len() } wg.Done() }() wg.Wait() }
// A header for a Go map. type hmap struct { // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go. // Make sure this stays in sync with the compiler's definition. count int// # live cells == size of map. Must be first (used by len() builtin) flags uint8 B uint8// log_2 of # of buckets (can hold up to loadFactor * 2^B items) noverflow uint16// approximate number of overflow buckets; see incrnoverflow for details hash0 uint32// hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing nevacuate uintptr// progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields }
// The len built-in function returns the length of v, according to its type: // Array: the number of elements in v. // Pointer to array: the number of elements in *v (even if v is nil). // Slice, or map: the number of elements in v; if v is nil, len(v) is zero. // String: the number of bytes in v. // Channel: the number of elements queued (unread) in the channel buffer; // if v is nil, len(v) is zero. // For some arguments, such as a string literal or a simple array expression, the // result can be a constant. See the Go language specification's "Length and // capacity" section for details. funclen(v Type)int
funcmain() { var wg sync.WaitGroup wg.Add(2) var ints = make([]int, 0, 1000) gofunc() { for i := 0; i < 1000; i++ { ints = append(ints, i) } wg.Done() }() gofunc() { for i := 0; i < 1000; i++ { ints = append(ints, i) } wg.Done() }() wg.Wait() fmt.Println(len(ints)) }
首先,slice不是协程安全的,自身也又没锁的保护,多协程访问存在并发问题:
1 2 3 4 5
type slice struct { array unsafe.Pointer lenint capint }
其次,append中有可能还会分配新的内存空间,切片可能指向了新的内存区域:
1 2 3 4 5 6 7 8 9 10
// The append built-in function appends elements to the end of a slice. If // it has sufficient capacity, the destination is resliced to accommodate the // new elements. If it does not, a new underlying array will be allocated. // Append returns the updated slice. It is therefore necessary to store the // result of append, often in the variable holding the slice itself: // slice = append(slice, elem1, elem2) // slice = append(slice, anotherSlice...) // As a special case, it is legal to append a string to a byte slice, like this: // slice = append([]byte("hello "), "world"...) funcappend(slice []Type, elems ...Type) []Type