// 在一个单独的 Go 协程计算平方和,而在另一个协程计算立方和,最后在 Go 主协程把平方和与立方和相加 package main
import ( "fmt" )
funccalcSquares(number int, squareop chanint) { // 计算平方和 sum := 0 for number != 0 { digit := number % 10 sum += digit * digit number /= 10 } squareop <- sum }
funccalcCubes(number int, cubeop chanint) { // 计算立方和 sum := 0 for number != 0 { digit := number % 10 sum += digit * digit * digit number /= 10 } cubeop <- sum }
funcproducer(chnl chanint) { for i := 0; i < 10; i++ { chnl <- i } close(chnl) // 关闭信道 }
funcmain() { ch1 := make(chanint) go producer(ch1) for { v, ok := <-ch1 if ok == false { // 如果 ok 等于 false,说明信道已经关闭,于是退出 for 循环 break } fmt.Println("Received ", v, ok) } ch2 := make(chanint) go producer(ch2) for v := range ch2 { fmt.Println("Received ",v) // 一旦关闭了信道 ch2 ,循环会自动结束 } }
funcwrite(ch chanint) { for i := 0; i < 5; i++ { ch <- i fmt.Println("successfully wrote", i, "to ch") // 写入 2 个元素时,阻塞 } close(ch) } funcmain() { ch := make(chanint, 2) // 容量为 2 的缓冲信道 go write(ch) // 缓冲信道传递给了 write 协程 time.Sleep(2 * time.Second) // 主协程休眠 2 秒,此时 write 协程在并发运行 for v := range ch { fmt.Println("read value", v,"from ch") time.Sleep(2 * time.Second) } } // 打印结果 successfully wrote 0 to ch successfully wrote 1 to ch read value 0 from ch successfully wrote 2 to ch read value 1 from ch successfully wrote 3 to ch read value 2 from ch successfully wrote 4 to ch read value 3 from ch read value 4 from ch
4.2. 缓冲信道长度和容量
容量:指信道可以存储的值的数量
长度:指信道中当前排队的元素个数
1 2 3 4 5 6 7 8 9
funcmain() { ch := make(chanstring, 3) ch <- "naveen" ch <- "paul" fmt.Println("capacity is", cap(ch)) // capacity is 3 fmt.Println("length is", len(ch)) // length is 2 fmt.Println("read value", <-ch) // read value naveen fmt.Println("new length is", len(ch)) // new length is 1 }
5. 工作池
5.1. WaitGroup
WaitGroup 用于实现工作池,其用于等待一批 Go 协程执行结束。程序控制会一直阻塞,直到这些协程全部执行完毕。WaitGroup 使用计数器来工作。
funcmain() { no := 3 var wg sync.WaitGroup // 创建变量,初始值为零值 for i := 0; i < no; i++ { wg.Add(1) // 计数器变为 3 go process(i, &wg) // 创建了 3 个协程,此处必须使用 wg 地址,否则每个 Go 协程将会得到一个 WaitGroup 值的拷贝 } wg.Wait() // 主协程等待计数器变为 0 fmt.Println("All go routines finished executing") }
type Job struct { id int randomno int } type Result struct { job Job sumofdigits int }
var jobs = make(chan Job, 10) var results = make(chan Result, 10)
funcdigits(number int)int { sum := 0 no := number for no != 0 { digit := no % 10 sum += digit no /= 10 } time.Sleep(2 * time.Second) return sum } funcworker(wg *sync.WaitGroup) { for job := range jobs { output := Result{job, digits(job.randomno)} results <- output } wg.Done() } funccreateWorkerPool(noOfWorkers int) { var wg sync.WaitGroup for i := 0; i < noOfWorkers; i++ { wg.Add(1) go worker(&wg) } wg.Wait() close(results) } funcallocate(noOfJobs int) { for i := 0; i < noOfJobs; i++ { randomno := rand.Intn(999) job := Job{i, randomno} jobs <- job } close(jobs) } funcresult(done chanbool) { for result := range results { fmt.Printf("Job id %d, input random no %d , sum of digits %d\n", result.job.id, result.job.randomno, result.sumofdigits) } done <- true } funcmain() { startTime := time.Now() noOfJobs := 100 go allocate(noOfJobs) done := make(chanbool) go result(done) noOfWorkers := 10 createWorkerPool(noOfWorkers) <-done endTime := time.Now() diff := endTime.Sub(startTime) fmt.Println("total time taken ", diff.Seconds(), "seconds") }