go 通道的运用(控制并发的数量)

无缓冲通道:同步通道

//对无缓冲channel类型的发送与接收操作,一定要放在两个不同的Goroutine中进行,否则会导致deadlock。
//无缓冲通道,必须接收和发送都准备好了才能执行。否则会阻塞。
//所以无缓冲通道相当于是同步通道了。
var helloChan = make(chan struct{})

func Test33() {
	fmt.Println("数一下羊吧~~~")
	go SaySheep()
	<-helloChan //这里会暂时阻塞直到SaySheep遍历执行输出10只羊后收到helloChan通道发送的值才会继续下一步
	fmt.Println("you are bad bad")
}

func SaySheep() {
	for i := 0; i < 10; i++ {
		fmt.Println("🐏")
	}
	helloChan <- struct{}{} //空结构体不占用内存
}

输出结果:
在这里插入图片描述

有缓冲通道:控制协程、并发的数量

//利用有缓冲通道控制协程的数量,利用waitGroup控制协程的结束
var wg sync.WaitGroup

func Test35() {
	//利用有缓冲通道控制协程数量为3
	ch := make(chan struct{}, 3)
	for i := 0; i < 20; i++ {
		wg.Add(1)
		//这里缓冲通道写满了3个数据后,就会阻塞,等待Weekend方法中发送通道里的数据,才能继续执行
		ch <- struct{}{}
		go Weekend(ch, i)
	}
	wg.Wait()
}

func Weekend(ch chan struct{}, i int) {
	fmt.Println("周末拉", i)
	fmt.Println(" goroutine count = ", runtime.NumGoroutine())
	// time.Sleep(time.Duration(i) * time.Second)
	<-ch
	wg.Done()
}

输出结果:
在这里插入图片描述

无缓冲通道也可以控制并发的数量

//无缓冲通道控制协程数量
//思想:开启固定的goroutine池,然后设置无缓冲的通道作为接收任务的中介,固定的协程读取到通道中任务就执行任务。
var wg sync.WaitGroup

func Test36() {
	var cowChan = make(chan string)
	var go_num = 3 //指定协程的数量为3
	for i := 0; i < go_num; i++ {
		go CallCowBoy(cowChan)
	}
	for i := 0; i < 20; i++ {
		SendTask(cowChan, i)
		//也可以直接写在这里
		// wg.Add(1)
		// cowChan <- "🐂🤠" + strconv.Itoa(i)
	}
	wg.Wait()
}

func CallCowBoy(ch chan string) {
	for v := range ch {
		fmt.Printf("%s are very busy \n", v)
		fmt.Println(" goroutine count = ", runtime.NumGoroutine())
		wg.Done()
	}
}

func SendTask(ch chan string, i int) {
	wg.Add(1)
	ch <- "🐂🤠" + strconv.Itoa(i)
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Golang 中可以通过 goroutine 和 channel 实现并发控制。 1. 使用 Goroutine 可以使用 `go` 关键字创建 goroutine,但是如果创建太多的 goroutine,会导致系统资源的浪费,因此我们可以使用 `sync.WaitGroup` 来控制 goroutine 数量。 示例代码: ```go package main import ( "fmt" "sync" ) func worker(id int, wg *sync.WaitGroup) { fmt.Printf("Worker %d starting\n", id) // 模拟工作 for i := 0; i < 1000000000; i++ { } fmt.Printf("Worker %d done\n", id) wg.Done() } func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go worker(i, &wg) } wg.Wait() fmt.Println("All workers done") } ``` 在上面的示例中,我们创建了 10 个 worker,但是每次只有 3 个 worker 在并发执行,其他的 worker 在等待。 2. 使用 Channel 我们可以使用 channel 来限制 goroutine 的数量,当 channel 中的值满了时,新的 goroutine 就会被阻塞,直到有空余的位置。 示例代码: ```go package main import ( "fmt" ) func worker(id int, jobs <-chan int, results chan<- int) { for j := range jobs { fmt.Printf("Worker %d starting job %d\n", id, j) // 模拟工作 for i := 0; i < 1000000000; i++ { } fmt.Printf("Worker %d finished job %d\n", id, j) results <- j * 2 } } func main() { const numJobs = 10 jobs := make(chan int, numJobs) results := make(chan int, numJobs) // 创建 3 个 worker for i := 0; i < 3; i++ { go worker(i, jobs, results) } // 添加任务 for j := 0; j < numJobs; j++ { jobs <- j } close(jobs) // 获取结果 for a := 0; a < numJobs; a++ { <-results } } ``` 在上面的示例中,我们创建了 3 个 worker,但是只有 10 个任务,因此可以使用一个大小为 10 的 channel 来限制并发数量。每个 worker 从 jobs channel 中获取任务,完成后将结果发送到 results channel 中。最后从 results channel 中获取所有的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值