当前位置: 首页 > article >正文

玩转goroutine:Golang中对goroutine的应用

文章目录

    • 前言
    • 需求说明
    • 目录结构说明
    • 需求拆分
      • 步骤一:配置HTTP服务
      • 步骤二:创建并发任务的实现
        • 代码解释
      • 步骤三:启动服务并测试
    • 总结以及进阶优化

前言

上一篇文章讲到了goroutine的基本原理和概念的理解,本次将基于 玩转goroutine:Golang中对goroutine的理解述 这篇文章的内容来写一个API接口,实现goroutine并发处理任务。

需求说明

本次将创建一个简单的示例,展示如处理并发请求。我们将从具体的目录结构出发,实现一个/process的API接口,触发的时候会启动多个goroutine来并发处理任务,并且使用sync.WaitGroup来等待所有并发任务完成。

目录结构说明

  • cmd/web-app/main.go:程序主入口,启动HTTP服务
  • internal/home/model.go:存放需求相关的业务逻辑
  • internal/user/handle.go:处理用户请求相关的代码
  • pkg/auth/jwt.go:用于认证的JWT代码(本次暂时用不到,保留作为示例)
  • pkg/config/config.go:全局配置文件

需求拆分

  • /process接口中,接收到请求后,启动多个goroutine来并发处理任务。
  • 每个goroutine模拟一个简单的任务(比如打印任务ID,模拟耗时操作等等)
  • 在所有任务完成后,返回一个成功响应到接口。

步骤一:配置HTTP服务

cmd/web-app/main.go中,设置HTTP服务,注册/process接口,并启动服务

// @title           My E-Commerce API
// @version         1.0
// @description     This is the API documentation for My E-Commerce platform.
// @termsOfService  http://example.com/terms/

// @contact.name    API Support
// @contact.url     http://example.com/support
// @contact.email   support@example.com

// @license.name    MIT
// @license.url     https://opensource.org/licenses/MIT

// @host            localhost:8088
// @BasePath
package main

import (
	"database/sql"
	"log"
	"my-ecommerce-app/internal/task" // 引入任务处理模块
	"my-ecommerce-app/pkg/config"

	_ "my-ecommerce-app/docs"

	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql" // 导入 MySQL 驱动
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
)

func main() {
	config.LoadConfig() // 加载配置

	// 使用配置连接数据库
	dsn := config.Appconfig.DBUser + ":" + config.Appconfig.DBPassword + "@tcp(" + config.Appconfig.DBHost + ")/" + config.Appconfig.DBName
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		log.Fatalf("无法连接到数据库:%v", err)
	}
	defer db.Close()

	// 数据库连接
	if err = db.Ping(); err != nil {
		log.Fatalf("数据库连接失败:%v", err)
	}

	// 初始化 Gin 引擎
	r := gin.New()

	// 注册路由
	r.GET("/api/process", task.ProcessHandler)
	// 添加swagger 路由
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
	// 启动服务
	if err := r.Run(":8088"); err != nil {
		log.Fatalf("无法启动服务器:%v", err)
	}
}

步骤二:创建并发任务的实现

internal/user/handle.go中,实现并发处理任务的逻辑

package task

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"sync"
	"time"
)

// ProcessTask 模拟一个处理任务的函数
func ProcessTask(taskID int, wg *sync.WaitGroup) {
	// 在goroutine结束时通知WaitGroup
	defer wg.Done()

	// 模拟任务耗时
	fmt.Printf("Task %d started\n", taskID)
	time.Sleep(2 * time.Second) // 模拟耗时操作
	fmt.Printf("Task %d completed\n", taskID)
}

// ProcessHandler 处理并发任务请求的HTTP处理器
func ProcessHandler(c *gin.Context) {
	// 创建WaitGroup来同步goroutine
	var wg sync.WaitGroup

	// 假设我们要启动5个goroutine来并发处理任务
	taskCount := 5
	for i := 1; i <= taskCount; i++ {
		wg.Add(1) // 每启动一个goroutine,WaitGroup计数加1
		go ProcessTask(i, &wg) // 启动一个新的goroutine来处理任务
	}

	// 等待所有goroutine完成
	wg.Wait()

	// 返回响应
	c.JSON(200, gin.H{
		"message": "All tasks completed successfully!",
	})
}

代码解释
  1. ProcessTask函数:
    • 创建的一个模拟任务处理函数。它会接收一个taskIDsync.WaitGroup作为参数
    • 在函数结束时,我们调用wg.Done()来通知WaitGroup当前的goroutine已经完成。
  2. ProcessHandler函数:
    • 这是处理/process接口的HTTP处理器
    • 定义来一个sync.WaitGroup来确保所有的goroutine都完成后才返回响应到接口
    • 通过wg.Add(1)来告知WaitGroup有一个新的goroutine启动,每当一个任务完成时,调用wg.Done()
    • 最后,调用wg.Wait()来阻塞主线程,直到所有的goroutine都执行完毕。

步骤三:启动服务并测试

  • 启动Go服务:go run cmd/web-app/main.go
  • 访问http://127.0.0.1:8088/api/process来测试接口。在控制台可以看到并发任务的处理过程,任务完成后接口将返回All tasks completed successfully!

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结以及进阶优化

  • 任务处理过程中,我们模拟了time.Sleep来表示任务的耗时。在实际项目中,可以替换成实际的业务逻辑,比如数据库操作调用微服务等。
  • 如果任务数量较多,或者每个任务执行时间较长,考虑引入任务池(Worker Pool)来限制并发数,避免过多的goroutine造成系统资源的浪费
    对于错误处理和超时处理,可以在goroutine中添加适当的error返回和context控制

以上就是一个基于goroutine的并发处理API。有任何问题,欢迎在评论区与我互动,感谢各位的观看~


http://www.kler.cn/a/534084.html

相关文章:

  • Java进阶学习之路
  • 【机器学习与数据挖掘实战】案例11:基于灰色预测和SVR的企业所得税预测分析
  • 云原生周刊:K8s引领潮流
  • Noise Conditional Score Network
  • 【自学笔记】Agent的重点知识点-持续更新
  • Ubuntu 下 nginx-1.24.0 源码分析 - ngx_sprintf_str 函数
  • js的 encodeURI() encodeURIComponent() decodeURI() decodeURIComponent() 笔记250205
  • 解决python写入csv时如000111样式的字符串前面的0被忽略掉的问题
  • DeepSeek-R1:开源机器人智能控制系统的革命性突破
  • Linux中安装rabbitMQ
  • 【含文档+PPT+源码】Python爬虫人口老龄化大数据分析平台的设计与实现
  • .net framework 4.5 的项目,用Mono 部署在linux
  • 【算法篇】选择排序
  • Mysql:数据库
  • docker单机运行环境的zabbix升级实战(从6.2.6升级到7.2.3)
  • Centos 8 离线升级openssh 9.9
  • Linux下线程间同步实现方式详解
  • ZooKeeper单节点详细部署流程
  • 【Kubernetes Pod间通信-第3篇】Kubernetes中Pod与ClusterIP服务之间的通信
  • OSPF基础(1)
  • JDK 中 NIO 框架设计与实现:深入剖析及实战样例
  • DES 3DES 简介 以及 C# 和 js 实现【加密知多少系列_2】
  • 以太网总线多功能数据采集卡,16路2M同步模拟量采集卡 NET9784A/B
  • 《Python预训练视觉和大语言模型》:从DeepSeek到大模型实战的全栈指南
  • Go语言的转义字符
  • LeetCode - #198 打家劫舍