go 利用channel控制并发

任务数量为50,并发在5,全部都要执行

Go 复制代码
package main

import (
	"fmt"
	"time"
)

type Con struct {
	num  int
	time string
}

func main() {

		//channel实现并发控制
	// 定义同时执行的任务数量
	concurrencyLevel := 5
	//总任务数
	totalTask := 50

	// 创建一个有缓冲的 channel 用于控制并发数
	taskChan := make(chan int, concurrencyLevel)

	// 创建一个 channel 用于标记所有任务完成
	doneChan := make(chan *Con, totalTask)

	// 启动指定数量的 goroutine 来并发执行任务
	for i := 0; i < concurrencyLevel; i++ {
		go concurrentTask(taskChan, doneChan)
	}

	// 发送任务到 taskChan

	//循环发送任务,保证每个任务都能发送到,如果发送任务时 taskChan 阻塞,等待一段时间再重试
	for i := 1; i <= totalTask; i++ {
		select {
		// 发送任务到 taskChan
		case taskChan <- i:
			//fmt.Printf("任务 %d 已发送\n", i)
		default:
			fmt.Println("任务发送阻塞,等待空闲...", i)
			// 等待 1 秒钟再重试
			time.Sleep(1 * time.Second)
			i--
		}
	}

	// 关闭 taskChan,通知所有的 goroutine 没有更多的任务
	close(taskChan)

	// 关闭 doneChan
	close(doneChan)

	 等待所有任务完成,并关闭 doneChan
	for res := range doneChan {
		fmt.Printf("任务 %d 完成, 完成时间:%s\n", res.num, res.time)
	}

	fmt.Println("所有任务已完成")

}


// 模拟一个并发执行的任务
func concurrentTask(taskChan chan int, doneChan chan *Con) {
	defer func() {
		// 捕获 panic,recover() 函数可以让程序从 panic 中恢复
		if r := recover(); r != nil {
			fmt.Println("任务发生panic,正在恢复:", r)
		}
	}()

	// 从 taskChan 中获取任务
	for task := range taskChan {
		fmt.Printf("处理任务 %d\n", task)
		time.Sleep(1 * time.Second) // 模拟任务执行时间
		//任务执行完毕,将任务结果发送到 doneChan
		doneChan <- &Con{num: task, time: time.Now().Format("2006-01-02 15:04:05")}
	}

}

任务数量为50,并发在5,遇到阻塞的就不再执行

Go 复制代码
package main

import (
	"fmt"
	"time"
)

type Con struct {
	num  int
	time string
}

func main() {

//channel实现并发控制
	// 定义同时执行的任务数量
	concurrencyLevel := 5
	//总任务数
	totalTask := 50

	// 创建一个有缓冲的 channel 用于控制并发数
	taskChan := make(chan int, concurrencyLevel)

	// 创建一个 channel 用于标记所有任务完成
	doneChan := make(chan *Con, totalTask)

	// 启动指定数量的 goroutine 来并发执行任务
	for i := 0; i < concurrencyLevel; i++ {
		go concurrentTask(taskChan, doneChan)
	}

	// 发送任务到 taskChan

	//循环发送任务,保证每个任务都能发送到,如果发送任务时 taskChan 阻塞,等待一段时间再重试
	for i := 1; i <= totalTask; i++ {
		select {
		// 发送任务到 taskChan
		case taskChan <- i:
			//fmt.Printf("任务 %d 已发送\n", i)
		default:
			fmt.Println("任务发送阻塞,等待空闲...", i)
		}
	}

	// 关闭 taskChan,通知所有的 goroutine 没有更多的任务
	close(taskChan)

	// 关闭 doneChan
	close(doneChan)

	 等待所有任务完成,并关闭 doneChan
	for res := range doneChan {
		fmt.Printf("任务 %d 完成, 完成时间:%s\n", res.num, res.time)
	}

	fmt.Println("所有任务已完成")

}

// 模拟一个并发执行的任务
func concurrentTask(taskChan chan int, doneChan chan *Con) {
	defer func() {
		// 捕获 panic,recover() 函数可以让程序从 panic 中恢复
		if r := recover(); r != nil {
			fmt.Println("任务发生panic,正在恢复:", r)
		}
	}()

	// 从 taskChan 中获取任务
	for task := range taskChan {
		fmt.Printf("处理任务 %d\n", task)
		time.Sleep(1 * time.Second) // 模拟任务执行时间
		//任务执行完毕,将任务结果发送到 doneChan
		doneChan <- &Con{num: task, time: time.Now().Format("2006-01-02 15:04:05")}
	}

}
相关推荐
HuiSoul20043 分钟前
Spring MVC
java·后端·spring mvc
Flobby5291 小时前
Go 语言中的结构体、切片与映射:构建高效数据模型的基石
开发语言·后端·golang
lsx2024062 小时前
Vue.js 响应接口:深度解析与实践指南
开发语言
froginwe112 小时前
Vue.js 样式绑定
开发语言
摇滚侠3 小时前
面试实战 问题二十四 Spring 框架中循环依赖问题的解决方法
java·后端·spring
GetcharZp4 小时前
C++日志库新纪元:为什么说spdlog是现代C++开发者必备神器?
c++·后端
Algebraaaaa4 小时前
为什么C++主函数 main 要写成 int 返回值 | main(int argc, char* argv[]) 这种写法是什么意思?
开发语言·c++
三木水4 小时前
Spring-rabbit使用实战七
java·分布式·后端·spring·消息队列·java-rabbitmq·java-activemq
快乐就是哈哈哈5 小时前
一篇文章带你玩转 EasyExcel(Java Excel 报表必学)
后端
快乐就是哈哈哈5 小时前
手把手教你用 Java 写出贪吃蛇小游戏(附源码)
后端