在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一、Goroute1. 进程和线程
2. 并发和并行
3. 协程和线程
package main import ( "fmt" "time" ) func test() { var i int for { fmt.Println(i) time.Sleep(time.Second) i++ } } func main() { go test() time.Sleep(time.Second * 10) // for { // fmt.Println("i' running in main") // time.Sleep(time.Second) // } } 4. goroutine调度模型
5. 如何设置golang运行的cpu核数package main import ( "fmt" "sync" "time" ) type task struct { n int } var ( m = make(map[int]uint64) lock sync.Mutex // 互斥锁 ) func calc(t *task) { var sum uint64 sum = 1 for i := uint64(1); i < uint64(t.n); i++ { sum *= i } fmt.Println(t.n, sum) lock.Lock() m[t.n] = sum lock.Unlock() } func main() { for i := 0; i < 16; i++ { t := &task{n: i} go calc(t) } time.Sleep(time.Second * 10) lock.Lock() for k, v := range m { fmt.Printf("%d! = %v\n", k, v) } lock.Unlock() } 6. 协程管理golang 同步等待所有协程执行完毕sync WaitGroup golang的sync的包有一个功能WaitGroup
func (wg *WaitGroup) Add(delta int):等待协程的数量。 func (wg *WaitGroup) Done(): 减少waitgroup线程等待线程数量的值,一般在协程完成之后执行。 func (wg *WaitGroup) Wait():wait方法一般在主线程调用,阻塞直到group计数减少为0。 示例 package main import ( "fmt" "sync" "time" ) func main() { var wg sync.WaitGroup for i := 0; i < 5; i = i + 1 { wg.Add(1) go func(n int) { // defer wg.Done() defer wg.Add(-1) EchoNumber(n) }(i) } wg.Wait() } func EchoNumber(i int) { time.Sleep(3e9) fmt.Println(i) }
二、Channel1.不同的goroutine之间如何进行通讯?a. 全局变量和锁同步 b. Channel 2. channel概念a. 类似unix中管道(pipe) b. 先进先出 c. 线程安全,多个goroutine同时访问,不需要de加锁 d. channel是有类型的,一个整数的channel只能存放整数 3. channel声明var 变量名 chan 类型 var test chan int var test chan string var test chan map[string]string var test chan stu var test chan *stu 4. channel初始化使用make进行初始化,比如: var test chan int test = make(chan int, 10) var test chan string test = make(chan string, 10) 5. channel基本操作1. 从channel读取数据 var testChan chan int testChan = make(chan int, 10) var a int a = <- testChan 2. 从channel写入数据 var testChan chan int testChan = make(chan int, 10) var a int = 10 testChan <- a package main import ( "fmt" "time" ) func write(ch chan int) { for i := 0; i < 100; i++ { ch <- i fmt.Println("put data: ", i) } } func read(ch chan int) { for { var b int b = <-ch fmt.Println(b) time.Sleep(time.Second) } } func main() { intChan := make(chan int, 10) go write(intChan) go read(intChan) time.Sleep(time.Second * 10) } 6.channel阻塞7. 带缓冲区的channel1. 如下所示,testChan 只能放一个元素 testChan := make(chan int) var a int a = <- testChan 2. 如下所示,testChan是带缓冲区的chan,一次可以放10个元素 testChan = make(chan int, 10) var a int testChan <- a package main import ( "fmt" ) func send(ch chan<- int, exitChan chan struct{}) { for i := 0; i < 10; i++ { ch <- i } close(ch) var a struct{} exitChan <- a } func recv(ch <-chan int, exitChan chan struct{}) { for { v, ok := <-ch if !ok { break } fmt.Println(v) } var a struct{} exitChan <- a } func main() { var ch chan int ch = make(chan int, 10) exitChan := make(chan struct{}, 2) go send(ch, exitChan) go recv(ch, exitChan) var total = 0 for _ = range exitChan { total++ if total == 2 { break } } } package main import "fmt" type student struct { name string } func main() { var intChan chan int intChan = make(chan int, 10) intChan <- 10 var stringChan chan map[string]string stringChan = make(chan map[string]string, 10) m := make(map[string]string, 16) m["stu01"] = "001" m["stu01"] = "002" stringChan <- m var stuChan chan *student stuChan = make(chan *student, 10) stu := student{name: "stud01"} stuChan <- &stu var stuInterChan chan interface{} stuInterChan = make(chan interface{}, 10) stu1 := student{name: "stu01"} stuInterChan <- &stu1 var stu01 interface{} stu01 = <-stuInterChan fmt.Println(stu01) var stu02 *student stu02, ok := stu01.(*student) if !ok { fmt.Println("can not convert") return } fmt.Println(stu02) } 8. chan之间的同步package main import ( "fmt" ) func calc(taskChan chan int, resChan chan int, exitChan chan bool) { for v := range taskChan { flag := true for i := 2; i < v; i++ { if v%i == 0 { flag = false break } } if flag { resChan <- v } } fmt.Println("exit") exitChan <- true } func main() { intChan := make(chan int, 1000) resultChan := make(chan int, 1000) exitChan := make(chan bool, 8) go func() { for i := 0; i < 100000; i++ { intChan <- i } close(intChan) }() for i := 0; i < 8; i++ { go calc(intChan, resultChan, exitChan) } // 等待所有的groutine全部退出 go func() { for i := 0; i < 8; i++ { <-exitChan fmt.Println("wait goroute", i, "exited") } close(resultChan) }() for v := range resultChan { fmt.Println(v) } } package main import ( "fmt" ) func send(ch chan int, exitChan chan struct{}) { for i := 0; i < 10; i++ { ch <- i } close(ch) var a struct{} exitChan <- a } func recv(ch chan int, exitChan chan struct{}) { for { v, ok := <-ch if !ok { break } fmt.Println(v) } var a struct{} exitChan <- a } func main() { ch := make(chan int, 10) exitChan := make(chan struct{}, 2) go send(ch, exitChan) go recv(ch, exitChan) var total = 0 for _ = range exitChan { total++ if total == 2 { break } } } 9.for range遍历chanpackage main import "fmt" func main() { var ch chan int ch = make(chan int, 1000) for i := 0; i < 1000; i++ { ch <- i } close(ch) for v := range ch { fmt.Println(v) } } 10. chan的关闭1. 使用内置函数close进行关闭,chan关闭之后,for range遍历chan中已经放入的元素 2. 使用内置函数close进行关闭, chan关闭之后,没有使用for range的写法,需要判断chan是否关闭。 示例 package main import "fmt" func main() { var ch chan int ch = make(chan int, 10) for i := 0; i < 10; i++ { ch <- i } close(ch) for { var b int b, ok := <-ch if ok == false { fmt.Println("chan is close") break } fmt.Println(b) } } 11. chan的只读和只写a. 只读chan的声明 var 变量的名字 <-chan int var readChan <-chan int b.只写chan的声明 var 变量的名字 chan <- int var writeChan chan <- int package main import ( "bufio" "fmt" "io" "os" ) func main() { file, err := os.Open("test.log") if err != nil { fmt.Println(err) return } defer file.Close() // 带缓存区的文件读写 reader := bufio.NewReader(file) var line []byte for { data, prefix, err := reader.ReadLine() if err == io.EOF { break } line = append(line, data...) if !prefix { fmt.Printf("data: %s\n", string(data)) line = line[:] } } // fmt.Println(line) } 12.对chan进行select操作package main import ( "fmt" "time" ) func main() { var ch chan int ch = make(chan int, 10) ch2 := make(chan int, 10) go func() { var i int for { ch <- i time.Sleep(time.Second) ch2 <- i * i time.Sleep(time.Second) i++ } }() for { select { case v := <-ch: fmt.Println(v) case v := <-ch2: fmt.Println(v) case <-time.After(time.Second): fmt.Println("get data timeout") time.Sleep(time.Second) } // var b int // b = <-ch // fmt.Println(b) } } 13.定时器的使用package main import ( "runtime" "time" ) func main() { num := runtime.NumCPU() runtime.GOMAXPROCS(num - 1) for i := 0; i < 1024; i++ { go func() { for { select { case <-time.After(time.Microsecond): // fmt.Println("get data timeout") } } }() } time.Sleep(time.Second * 1000) } 14.一次定时器、超时控制package main import ( "fmt" "runtime" "time" ) func main() { num := runtime.NumCPU() runtime.GOMAXPROCS(num - 1) for i := 0; i < 16; i++ { go func() { for { t := time.NewTicker(time.Second) select { case <-time.After(time.Microsecond): fmt.Println("timeout") } t.Stop() } }() } time.Sleep(time.Second * 1000) } 15.goroutine中使用recoverpackage main import ( "fmt" "runtime" "time" ) func test() { defer func() { if err := recover(); err != nil { fmt.Println("panic:", err) } }() var m map[string]int m["stu"] = 100 } func calc() { for { fmt.Println("i'm calc") time.Sleep(time.Second) } } func main() { num := runtime.NumCPU() runtime.GOMAXPROCS(num - 1) go test() for i := 0; i < 100; i++ { go calc() } time.Sleep(time.Second * 1000) } 实战package response import "sync" type ChannelController struct { Channel chan bool WaitGroup *sync.WaitGroup } func UpdateCasbin2(casbinRecive request.CasbinInReceive) error { e := Casbin() // 清空指定用户所有权限,若更新权限为空 则返回 ClearCasbin(e, 0, casbinRecive.RoleId) if len(casbinRecive.CasbinInfos) == 0 { return nil } // 更新用户权限 var ChanController response.ChannelController ChanController.Channel = make(chan bool, len(casbinRecive.CasbinInfos)) ChanController.WaitGroup = &sync.WaitGroup{} ChanController.WaitGroup.Add(len(casbinRecive.CasbinInfos)) for _, v := range casbinRecive.CasbinInfos { go AddCasbin(e, v, casbinRecive.RoleId, ChanController) } ChanController.WaitGroup.Wait() close(ChanController.Channel) for addFlag := range ChanController.Channel{ if !addFlag { return errors.New("存在相同api,添加失败,请联系管理员") } } return nil } func AddCasbin(e *casbin.Enforcer, v request.CasbinInfo, roleId string, chan_contro response.ChannelController) { defer chan_contro.WaitGroup.Done() cm := model.CasbinRule{ Ptype: "p", RoleId: roleId, Path: v.Path, Method: v.Method, } chan_contro.Channel <- e.AddPolicy(cm.RoleId, cm.Path, cm.Method) } 三、单元测试
package main func add(a, b int) int { return a + b } func sub(a, b int) int { return a - b } package main import ( "encoding/json" "io/ioutil" ) type student struct { Name string Sex string Age int } func (p *student) Save() (err error) { data, err := json.Marshal(p) if err != nil { return } err = ioutil.WriteFile("stu.dat", data, 0755) return } func (p *student) Load() (err error) { data, err := ioutil.ReadFile("stu.dat") if err != nil { return } err = json.Unmarshal(data, p) return } package main import "testing" func TestAdd(t *testing.T) { r := add(2, 4) if r != 6 { t.Fatalf("add(2,4) error, expect:%d, actual:%d", 6, r) } t.Log("test add succ") } func TestSub(t *testing.T) { r := sub(2, 4) if r != -2 { t.Fatalf("sub(2,4) error, expect:%d, actual:%d", -2, r) } t.Logf("test sub succ") } package main import "testing" func TestSave(t *testing.T) { stu := &student{ Name: "stu01", Sex: "man", Age: 10, } err := stu.Save() if err != nil { t.Fatalf("save student failed: err%v", err) } } func TestLoad(t *testing.T) { stu := &student{ Name: "stu01", Sex: "man", Age: 10, } err := stu.Save() if err != nil { t.Fatalf("save student failed: err%v", err) } stu2 := &student{} err = stu2.Load() if err != nil { t.Fatalf("load student failed,err: %v", err) } if stu.Name != stu2.Name { t.Fatalf("load student failed, Name not equal") } if stu.Age != stu2.Age { t.Fatalf("load student failed, Age not equal") } if stu.Sex != stu2.Sex { t.Fatalf("load student failed, Sex not equal") } } package main
|
请发表评论