1.基础知识
make(chan int, 1) 和 make (chan int) :前者有缓冲区,后者无。前者缓冲区满时阻塞,后者只要数据没被读出就会阻塞
2.并发实践
使用不同的方法实现并发打印数组
func Worker(i, n int) {
fmt.Println(fmt.Sprintf("协程:%v-----输出:%v", i, n))
}
1)每个打印起一个协程
func test() {
var wg sync.WaitGroup
for i := 0; i < 50; i++ {
num := i
go func() {
wg.Add(1)
Worker(num, num)
wg.Done()
}()
}
wg.Wait()
}
部分输出结果:
这个方法不够灵活,根据循环个数创建协程,若循环次数多,且执行的任务时间长时,不适用此方法
2)固定协程的个数
func test() {
urls := make(chan int, 50)
for i := 0; i < 50; i++ {
urls <- i
}
close(urls)
var wg sync.WaitGroup
for j := 0; j < 4; j++ {
wg.Add(1)
n := j
go func() {
defer wg.Done()
for url := range urls {
Worker(n, url)
time.Sleep(1e9) //worker方法执行时间短,加上可以使worker均匀分配
}
}()
}
wg.Wait()
}
部分输出结果:
这个方法需要将打印的数据放入到缓冲区内,下面是无需放入版本
func test() {
url := make([]int, 0)
for i := 0; i < 50; i++ {
url = append(url, i)
}
maxNum := 4
token := make(chan int, maxNum) //定义一个令牌,和协程最大个数一致
for i := 0; i < maxNum; i++ {
token <- i //给令牌初始化
}
var wg sync.WaitGroup
for u := range url {
n := u
wg.Add(1)
i := <-token //当前执行的协程,释放令牌权限
go func() {
Worker(i, n)
time.Sleep(1e9)
wg.Done()
token <- i //重新获取到权限
}()
}
wg.Wait()
}
部分输出结果: