两个常见的Go测试题:
package main
import (
"fmt"
"sync"
"time"
)
/******************* 题1:限制协程个数 *******************/
// 任务函数
func job(i int, limitChan chan struct{}) {
limitChan <- struct{}{}
defer func() {
<- limitChan
}()
time.Sleep(1 * time.Second)
fmt.Printf("任务:%d已完成,当前协程数:%d\n", i, len(limitChan))
}
// limitChan限制协程数
func RunGoroutine() {
limitChan := make(chan struct{}, 10) // 最大协程数限制为10个
for i := 0; i < 100; i++ {
go job(i, limitChan)
}
}
/******************* 题2:按顺序打印cat、dog、fish各100次 *******************/
func PrintDog(dogChan chan struct{}, catChan, limitChan chan struct{}) {
wgDCF.Add(1)
<-dogChan
// limitChan <- struct{}{} // 本来dogChan可以进入的,但是有可能因为limitChan满了,导致无法执行 <- dogChan,从而导致死锁
defer func() {
wgDCF.Done()
// <-limitChan
}()
fmt.Println("Dog:", /*runtime.NumGoroutine(), len(limitChan)*/)
catChan <- struct{}{}
}
func PrintCat(catChan chan struct{}, fishChan, limitChan chan struct{}) {
wgDCF.Add(1)
<-catChan
// limitChan <- struct{}{}
defer func() {
wgDCF.Done()
// <-limitChan
}()
fmt.Println("Cat:", /*runtime.NumGoroutine(), len(limitChan)*/)
fishChan <- struct{}{}
}
func PrintFish(fishChan, catChan, limitChan chan struct{}) {
wgDCF.Add(1)
<-fishChan
// limitChan <- struct{}{}
defer func() {
wgDCF.Done()
// <-limitChan
}()
fmt.Println("Fish:", /*runtime.NumGoroutine(), len(limitChan)*/)
catChan <- struct{}{}
}
var wgDCF sync.WaitGroup
func DCF() {
limitChan := make(chan struct{}, 3) // 可省略:这里其实可以不加limitChan的,因为本身令牌就是按顺序传递的:dog->cat->fish,最多一个时刻就只能有一个limitChan
dogChan := make(chan struct{}, 1)
catChan := make(chan struct{}, 1)
fishChan := make(chan struct{}, 1)
defer func() {
defer close(limitChan)
defer close(dogChan)
defer close(catChan)
defer close(fishChan)
}()
dogChan <- struct{}{} // 先触发
for i := 0; i < 100; i++ {
go PrintDog(dogChan, catChan, limitChan)
go PrintCat(catChan, fishChan, limitChan)
go PrintFish(fishChan, dogChan, limitChan)
}
wgDCF.Wait()
fmt.Println("---DCF end---")
}
func main() {
// 1.限制协程数:
// RunGoroutine()
// 2.按顺序打印cat、dog、fish各100次
DCF()
for{} // 阻塞
}