[每周一更]-(第131期):Go并发协程总结篇

news2025/1/13 11:23:00

在这里插入图片描述

Go语言的并发是通过协程(goroutine)实现的。Go协程是轻量级的线程,允许多个任务同时执行,且Go运行时会高效地管理它们。在Go中使用并发协程的方式非常简便,也很强大。以下是一些关于Go协程的基础用法和并发控制方法:

文章目录

      • 1. 启动协程
      • 2. 使用 `sync.WaitGroup` 管理协程
      • 3. 使用通道(Channel)进行协程间通信
        • 创建并使用通道
        • 带缓冲的通道
      • 4. 使用 `select` 多路复用通道
      • 5. 使用 `sync.Mutex` 实现互斥锁
      • 6. 使用 `sync.Once` 确保只执行一次
        • 小结
      • 7.用 `context` 管理并发任务
        • 实际业务场景

1. 启动协程

要启动一个协程,只需要在函数调用前加上关键字 go

package main

import (
    "fmt"
    "time"
)

func printMessage(message string) {
    fmt.Println(message)
}

func main() {
    go printMessage("Hello from goroutine!")
    fmt.Println("Hello from main!")
    time.Sleep(time.Second) // 给协程时间执行完毕
}

在这个例子中,printMessage 函数会作为一个协程执行,因此main函数中的打印语句和协程可能会并行执行。

注意main函数运行完毕时,程序会立即退出,即使其他协程仍在执行。所以在这里用time.Sleep让主协程等待,确保子协程有时间完成工作。

2. 使用 sync.WaitGroup 管理协程

sync.WaitGroup 是Go提供的一个结构,可以用来等待一组协程完成。

package main

import (
    "fmt"
    "sync"
)

func printNumber(num int, wg *sync.WaitGroup) {
    defer wg.Done() // 调用Done来减少计数
    fmt.Println(num)
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 5; i++ {
        wg.Add(1) // 增加计数
        go printNumber(i, &wg)
    }
    wg.Wait() // 等待所有协程完成
    fmt.Println("All goroutines finished!")
}

3. 使用通道(Channel)进行协程间通信

通道是Go内置的并发控制机制,协程间可以通过通道进行数据传递,避免数据竞争。

channelnil非空空的满的没满
接收阻塞接收值阻塞接收值接收值
发送阻塞发送值发送值阻塞发送值
关闭panic关闭成功,读完数据后返回零值关闭成功,返回零值关闭成功,读完数据后返回零值关闭成功,读完数据后,返回零值

关闭后的通道有以下特点:

  • 对一个关闭的通道再发送值就会导致panic。
  • 对一个关闭的通道进行接收会一直获取值直到通道为空。
  • 对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值。
  • 关闭一个已经关闭的通道会导致panic。
创建并使用通道
package main

import (
    "fmt"
)

func sum(a, b int, resultChan chan int) {
    result := a + b
    resultChan <- result // 将结果发送到通道
}

func main() {
    resultChan := make(chan int) // 创建一个int类型的通道

    go sum(3, 5, resultChan) // 启动协程计算
    result := <-resultChan   // 从通道中接收结果
    fmt.Println("Sum:", result)
}
带缓冲的通道

Go支持缓冲通道,允许发送者发送多于一个数据而不需要立刻被接收。

package main

import (
    "fmt"
)

func main() {
    bufferedChan := make(chan int, 3) // 缓冲大小为3
    bufferedChan <- 1
    bufferedChan <- 2
    bufferedChan <- 3
    fmt.Println(<-bufferedChan)
    fmt.Println(<-bufferedChan)
    fmt.Println(<-bufferedChan)
}

4. 使用 select 多路复用通道

select 语句可以同时等待多个通道操作,执行第一个准备好的操作。

package main

import (
    "fmt"
    "time"
)

func main() {
    chan1 := make(chan string)
    chan2 := make(chan string)

    go func() {
        time.Sleep(2 * time.Second)
        chan1 <- "Message from channel 1"
    }()
    go func() {
        time.Sleep(1 * time.Second)
        chan2 <- "Message from channel 2"
    }()

    select {
    case msg1 := <-chan1:
        fmt.Println(msg1)
    case msg2 := <-chan2:
        fmt.Println(msg2)
    case <-time.After(3 * time.Second):
        fmt.Println("Timeout")
    }
}

5. 使用 sync.Mutex 实现互斥锁

当多个协程需要访问共享资源时,可以使用sync.Mutex来保证同一时间只有一个协程可以访问。

package main

import (
    "fmt"
    "sync"
)

var counter int
var mutex sync.Mutex

func increment(wg *sync.WaitGroup) {
    defer wg.Done()
    mutex.Lock()   // 加锁
    counter++
    mutex.Unlock() // 解锁
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go increment(&wg)
    }

    wg.Wait()
    fmt.Println("Final counter:", counter)
}

6. 使用 sync.Once 确保只执行一次

有些场景下,需要确保某段代码只执行一次(例如初始化配置),可以使用sync.Once

package main

import (
    "fmt"
    "sync"
)

var once sync.Once

func initialize() {
    fmt.Println("Initialized!")
}

func main() {
    for i := 0; i < 3; i++ {
        once.Do(initialize) // 只会执行一次
    }
}
小结
  • 启动协程:使用go关键字。
  • 等待协程完成:使用sync.WaitGroup
  • 协程间通信:使用通道(Channel)。
  • 通道多路复用:使用select
  • 互斥控制:使用sync.Mutex
  • 单次执行:使用sync.Once

Go的并发特性为编写高效的并发程序提供了强大支持,同时也有丰富的同步原语来避免竞态条件。

7.用 context 管理并发任务

使用 context.Context 可以优雅地管理并发任务,尤其是在需要统一控制超时、取消操作或共享上下文数据时。

实际业务场景
  1. 超时管理
    • API 请求或任务需要在一定时间内完成,否则强制取消,避免资源浪费。
  2. 任务协调
    • 多个并发任务共享相同的上下文状态,例如取消操作。
  3. 优雅退出
    • 确保并发任务能够响应外部取消信号,安全退出而非强制终止。
package main

import (
	"context"
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// 模拟一个工作函数
func worker(ctx context.Context, id int, wg *sync.WaitGroup) {
	defer wg.Done()

	for {
		select {
		case <-ctx.Done():
			// 任务被取消时结束
			fmt.Printf("Worker %d stopped: %v\n", id, ctx.Err())
			return
		default:
			// 模拟工作
			time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
			fmt.Printf("Worker %d is processing\n", id)
		}
	}
}

func main() {
	// 设置超时时间的上下文
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	// 创建 WaitGroup 来等待所有任务完成
	var wg sync.WaitGroup

	// 启动多个并发任务
	numWorkers := 5
	for i := 1; i <= numWorkers; i++ {
		wg.Add(1)
		go worker(ctx, i, &wg)
	}

	// 等待所有任务结束
	wg.Wait()
	fmt.Println("All workers stopped.")
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2275940.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ecdsa密钥在线生成工具

具体前往&#xff1a;ECC公钥私钥对在线生成器

llama.cpp 模型可视化工具 GGUF Visualizer

llama.cpp 模型可视化工具 GGUF Visualizer 1. GGUF Visualizer for VS Code (gguf-viz)1.1. Features1.2. Extension Settings References GGUF Visualizer https://marketplace.visualstudio.com/items?itemNameAgainstEntropy.gguf-viz 1. GGUF Visualizer for VS Code (g…

【DAPM杂谈之三】DAPM的初始化流程

本文主要分析DAPM的设计与实现 内核的版本是&#xff1a;linux-5.15.164&#xff0c;下载链接&#xff1a;Linux内核下载 主要讲解有关于DAPM相关的知识&#xff0c;会给出一些例程并分析内核如何去实现的 /**************************************************************…

HarmonyOS:@LocalBuilder装饰器: 维持组件父子关系

一、前言 当开发者使用Builder做引用数据传递时&#xff0c;会考虑组件的父子关系&#xff0c;使用了bind(this)之后&#xff0c;组件的父子关系和状态管理的父子关系并不一致。为了解决组件的父子关系和状态管理的父子关系保持一致的问题&#xff0c;引入LocalBuilder装饰器。…

Pytorch导出onnx模型并在C++环境中调用(含python和C++工程)

Pytorch导出onnx模型并在C环境中调用&#xff08;含python和C工程&#xff09; 工程下载链接&#xff1a;Pytorch导出onnx模型并在C环境中调用&#xff08;python和C工程&#xff09; 机器学习多层感知机MLP的Pytorch实现-以表格数据为例-含数据集和PyCharm工程中简单介绍了在…

git打补丁

1、应用场景 跨仓库升级 开发项目B使用的是开源项目A。开源项目A发现漏洞&#xff0c;作者进行了修复&#xff0c;我们可以通过使用git补丁的方式&#xff0c;将作者修改的内容复制到我 们的项目B中。 2、TortoiseGit方式 源仓库 格式化补丁 根据提交数量&#xff0c;生成…

计算机网络 (34)可靠传输的工作原理

前言 计算机网络可靠传输的工作原理主要依赖于一系列协议和机制&#xff0c;以确保数据在传输过程中能够准确无误地到达目的地。 一、基本概念 可靠传输指的是数据链路层的发送端发送什么&#xff0c;在接收端就收到什么&#xff0c;即保证数据的完整性、正确性和顺序性。由于网…

基于ADAS 与关键点特征金字塔网络融合的3D LiDAR目标检测原理与算法实现

一、概述 3D LiDAR目标检测是一种在三维空间中识别和定位感兴趣目标的技术。在自动驾驶系统和先进的空间分析中&#xff0c;目标检测方法的不断演进至关重要。3D LiDAR目标检测作为一种变革性的技术&#xff0c;在环境感知方面提供了前所未有的准确性和深度信息. 在这里&…

Vue3初学之常用的指令

v-bind&#xff1a;动态绑定属性 v-bind 用于动态绑定一个或多个属性&#xff0c;或一个组件 prop 到表达式的值。 v-model&#xff1a;双向数据绑定 见上篇 https://editor.csdn.net/md/?articleId145022994 v-if、v-else-if、v-else&#xff1a;条件渲染 v-show&…

docker中jenkins流水线式部署GitLab中springboot项目

本质就是将java项目拉取下来&#xff0c;并自动打包成docker镜像&#xff0c;运行 首先启动一个docker的jenkins 如果没有镜像使用我的镜像 通过网盘分享的文件&#xff1a;jenkins.tar 链接: https://pan.baidu.com/s/1VJOMf6RSIQbvW_V1zFD7eQ?pwd6666 提取码: 6666 放入服…

在ubuntu下对NFS做性能测试

安装NFS 首先&#xff0c;安装服务 sudo apt update sudo apt install nfs-kernel-server然后创建共享文件夹 # 请自定义你自己的共享目录 sudo mkdir -p /exports/nfs4/homes sudo chmod -R 777 /exports/nfs4/homes# 这个可以根据no_root_squash标致选择设置。 # 如果不设…

Open FPV VTX开源之默认MAVLink设置

Open FPV VTX开源之默认MAVLink设置 1. 源由2. 准备3. 连接4. 安装5. 配置6. 测试6.1 启动wfb-ng服务6.2 启动wfb-ng监测6.3 启动QGroundControl6.4 观察测试结果 7. 总结8. 参考资料9. 补充9.1 telemetry_tx异常9.2 DEBUG串口部分乱码9.3 PixelPilot软件问题 1. 源由 飞控图传…

26个开源Agent开发框架调研总结(2)

根据Markets & Markets的预测&#xff0c;到2030年&#xff0c;AI Agent的市场规模将从2024年的50亿美元激增至470亿美元&#xff0c;年均复合增长率为44.8%。 Gartner预计到2028年&#xff0c;至少15%的日常工作决策将由AI Agent自主完成&#xff0c;AI Agent在企业应用中…

mark 一下conductor github

Netflix 关闭conductor 后&#xff0c;后续https://orkes.io/content/ 继续在维护&#xff0c;github地址如下 https://github.com/conductor-oss/conductor 最新release为3.21.11

PyCharm文档管理

背景&#xff1a;使用PyCharmgit做文档管理 需求&#xff1a;需要PyCharm自动识别docx/xslx/vsdx等文件类型&#xff0c;并在PyCharm内点击文档时唤起系统内关联应用(如word、excel、visio) 设置步骤&#xff1a; 1、file -》 settings -》file types 2、在Files opened i…

嘉立创画原理图和PCB

一、环境 进入立创EDA官网 注册登录的环节就不介绍了。 登录账号后&#xff0c;选择专业版 二、原理图 工程中&#xff0c;有原理图和PCB&#xff0c;这里选择原理图 那么接下来就是进行绘制 元器件在如下区域搜索使用。 双击进行放置&#xff0c;也可以左键提前预览。 网…

科创驱动 | 华望系统科技荣膺西湖区年度前沿创新新锐企业

2025年1月3日&#xff0c;由中共西湖区党委、西湖区人民政府主办的“新年第一会”—西湖区科技创新大会在杭州隆重举行。大会现场揭晓了西湖区年度科技创新团队与项目&#xff0c;并发布了“2024西湖区科技十大事件”与“西湖区五大年度科技榜单”。杭州华望系统科技有限公司榜…

Monorepo设置:新手指南

Monorepo是一种项目代码管理方法&#xff0c;指在单个代码仓库中管理多个项目&#xff0c;有助于简化代码共享、版本控制、构建和部署的复杂性&#xff0c;并提供更好的可重用性和协作性。 简单理解&#xff1a;所有项目都在一个代码仓库中 &#x1f4e6;&#xff0c;但这并不意…

[Python学习日记-75] 计算机基础与网络

[Python学习日记-75] 计算机基础与网络 简介 计算机基础 什么是网络编程 计算机网络 简介 本篇主要介绍的计算机基础是浓缩的&#xff0c;这是因为我们主要学习的是 Python&#xff0c;而 Python 主要是为了开发应用程序的&#xff0c;并不会用它来开发操作系统和嵌入式程序…

1. Doris分布式环境搭建

一. 环境准备 本次测试集群采用3台机器hadoop1、hadoop2、hadoop3, Frontend和Backend部署在同一台机器上&#xff0c;Frontend部署3台组成高可用&#xff0c;Backend部署3个节点&#xff0c;组成3副本存储。 主机IP操作系统FrontendBackendhadoop1192.168.47.128Centos7Foll…