golang channle 管道
Posted 钢闸门的笔记收藏册
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang channle 管道相关的知识,希望对你有一定的参考价值。
管道的使用介绍
现在要计算 1-N 的各个数的阶乘,并且把各个数的阶乘放入到 map 中。最后显示出来。要求使用 goroutine 完成
package main import ( "fmt" ) var ( mymap = make(map[int]int, 10) ) func calc(n int) { res := 1 for i := 1; i <= n; i++ { res *= i } mymap[n] = res } func main() { for n := 1; n < 20; n++ { go calc(n) } for key, val := range mymap { fmt.Printf("map[%d]=%d\\n", key, val) } }
问题1:使用goroutine时,主线程执行结束,即使协程没有执行完毕也会结束,顾map没有结果
func main() { for n := 1; n < 20; n++ { go calc(n) } time.Sleep(time.Second * 3) // 加入睡眠 for key, val := range mymap { fmt.Printf("map[%d]=%d\\n", key, val) } }
问题2:fatal error:并发写
API server listening at: 127.0.0.1:4417 fatal error: concurrent map writes goroutine 36 [running]: runtime.throw(0x4e0144, 0x15) D:/programs/go/src/runtime/panic.go:608 +0x79 fp=0xc0000bff28 sp=0xc0000bfef8 pc=0x42e099 runtime.mapassign_fast64(0x4c2300, 0xc000072240, 0x12, 0x0) D:/programs/go/src/runtime/map_fast64.go:101 +0x41a fp=0xc0000bff90 sp=0xc0000bff28 pc=0x4110ea main.calc(0x12) D:/go_work/src/gortoutine/1/1.go:18 +0x94 fp=0xc0000bffd8 sp=0xc0000bff90 pc=0x4aa314 runtime.goexit() D:/programs/go/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc0000bffe0 sp=0xc0000bffd8 pc=0x456f41 created by main.main D:/go_work/src/gortoutine/1/1.go:23 +0x70 goroutine 1 [sleep]: time.Sleep(0xb2d05e00) D:/programs/go/src/runtime/time.go:105 +0x132 main.main() D:/go_work/src/gortoutine/1/1.go:26 +0x8f
排查方法:在运行某个程序时,如何知道是否存在资源竞争问题。 方法很简单,在编译该程序时,增加一个参数 -race 即可
D:\\go_work>1.exe ================== WARNING: DATA RACE Write at 0x00c00006e240 by goroutine 7: runtime.mapassign_fast64() D:/programs/go/src/runtime/map_fast64.go:92 +0x0 main.calc() D:/go_work/src/goroutine/1/1.go:18 +0x91 Previous write at 0x00c00006e240 by goroutine 6: runtime.mapassign_fast64() D:/programs/go/src/runtime/map_fast64.go:92 +0x0 main.calc() D:/go_work/src/goroutine/1/1.go:18 +0x91 Goroutine 7 (running) created at: main.main() D:/go_work/src/goroutine/1/1.go:23 +0x6f Goroutine 6 (finished) created at: main.main() D:/go_work/src/goroutine/1/1.go:23 +0x6f ================== map[5]=120 map[6]=720 map[8]=40320 map[13]=6227020800 ================== WARNING: DATA RACE Read at 0x00c0000b6068 by main goroutine: main.main() D:/go_work/src/goroutine/1/1.go:27 +0x103 Previous write at 0x00c0000b6068 by goroutine 19: main.calc() D:/go_work/src/goroutine/1/1.go:18 +0xa6 Goroutine 19 (finished) created at: main.main() D:/go_work/src/goroutine/1/1.go:23 +0x6f ================== map[14]=87178291200 map[4]=24 map[10]=3628800 map[16]=20922789888000 map[18]=6402373705728000 map[17]=355687428096000 map[19]=121645100408832000 map[1]=1 map[2]=2 map[7]=5040 map[11]=39916800 map[12]=479001600 map[15]=1307674368000 map[3]=6 map[9]=362880 Found 2 data race(s)
会提示存在两个数据竞争
低水平解决方法,给变量加锁。
package main import ( "fmt" "sync" "time" ) var ( mymap = make(map[int]int, 10) lock sync.Mutex ) func calc(n int) { res := 1 for i := 1; i <= n; i++ { res *= i } lock.Lock() mymap[n] = res lock.Unlock() } func main() { for n := 1; n < 20; n++ { go calc(n) } time.Sleep(time.Second * 10) for key, val := range mymap { lock.Lock() fmt.Printf("map[%d]=%d\\n", key, val) lock.Unlock() } }
这是个笨方法,大大影响程序性能
以上是关于golang channle 管道的主要内容,如果未能解决你的问题,请参考以下文章