Lock
go语言中有两种锁:互斥锁和读写锁
互斥锁Mutex
常用于对并发资源的限制 
如果不加锁,在协程中并发执行,最后结果可能非预期:
func TestLock(t *testing.T) {
	counter := 0
	for i := 0; i < 500; i++ {
		go func() {
			counter++
		}()
	}
	t.Logf("counter %d\n", counter) // 结果几乎都不是500
}
使用Mutex加锁后执行:
func TestMutexLock(t *testing.T) {
	counter := 0
	var mut sync.Mutex
	for i := 0; i < 500; i++ {
		go func() {
			defer func() {
				mut.Unlock()
			}()
			mut.Lock()
			counter++
		}()
	}
	time.Sleep(time.Second * 1) // 这里不加sleep结果不一定正确
	t.Logf("counter %d\n", counter) // 当sleep 1s且循环次数不算特别大时,结果是正确的
}
会注意到,使用Mutex加锁后,在最后输出结果前sleep了1s,如果不执行sleep,结果大概率是不正确的,为什么呢? 
因为主协程可能执行得比较快,导致还没计算出真正的结果就已经输出,因此sleep 
但这里可以提出一个新的问题,如何界定这个sleep的时间?有没有可能sleep设置得不够?因此引出新的方式WaitGroup
WaitGroup
func TestMutexWaitGroup(t *testing.T) {
	counter := 0
	var mut sync.Mutex
	var wg sync.WaitGroup
	for i := 0; i < 500; i++ {
		wg.Add(1)
		go func() {
			defer func() {
				mut.Unlock()
			}()
			mut.Lock()
			counter++
			wg.Done()
		}()
	}
	wg.Wait()
	t.Logf("counter %d\n", counter) // 结果几乎都不是500
}
读写锁RWMutex
1 RWLock读是非互斥锁,写是互斥锁  
2 读写锁的读锁可以重入,在已经有读锁的情况下,可以任意加锁 
3 在读锁没有全部解锁的情况下,写操作会阻塞直到所有读锁解锁 
4 写锁定的情况下,其他协程的读写都会被阻塞,直到写锁解锁 
5 读写锁本身是互斥的,读需要写锁都解锁,写需要读锁都解锁
channel
无buffer的channel
func server() string {
	time.Sleep(time.Second * 2)
	fmt.Println("run server...")
	return "server"
}
func serverChan() chan string {
	chanTest := make(chan string)
	for i := 0; i <= 100; i++ {
		go func() {
			ret := server()
			chanTest <- ret
		}()
	}
	return chanTest
}
func TestChannel(t *testing.T) {
	retChan := serverChan()
	t.Log(<-retChan)
}
有buffer的channel
以上代码,make chan的时候提供buffer长度:
chanTest := make(chan string)
select
select中的case表示随机取到其中一个,当包含time.After时,会看是否到达设置的时间,到达则表示超时,执行对应代码
多渠道选择
多个渠道,随机执行:
func TestSelectChan(t *testing.T) {
	retCh1 := serverChan()
	retCh2 := anotherServerChan()
	time.Sleep(time.Second * 2)
	select {
	case ret := <-retCh1:
		t.Logf("ret: %v\n", ret)
	case ret := <-retCh2:
		t.Logf("ret: %v\n", ret)
	case <-time.After(time.Second * 1):
		t.Log("break......")
	}
}
超时控制
上文中的case <-time.After(time.Second * 1)即为超时控制
channel的关闭与广播
向关闭的channel发送数据,会导致panic:
func closeChan() chan string {
	chanTest := make(chan string)
	for i := 0; i <= 10; i++ {
		go func() {
			chanTest <- "aaa"
		}()
	}
	close(chanTest)
	return chanTest
}
func TestSendCloseToChannelPanic(t *testing.T) {
	closeChan()
}
事实上,以上代码看起来好像是最后才关闭的chan,但实际上协程可能没执行完,当for循环的次数足够多,几乎都会出现以下报错:
panic: send on closed channel
对于此案例来说,要想解决问题,可以尝试之前用过的加锁方式: