Go语言并发编程:轻松驾驭多线程世界(九)

Go语言并发编程:轻松驾驭多线程世界在这里插入图片描述

在这里插入图片描述
在现代编程中,并发 是让你的程序变得更强大、更高效的关键技能。幸运的是,Go语言提供了一种简单、直观的方式来处理并发任务,使用轻量级的 GoroutineChannel,让我们能够像指挥交通一样简单地处理多个任务。今天,我们将一起深入探讨Go语言的并发编程模型,轻松搞定并发编程!

1. Goroutine:Go语言的轻量级线程

什么是 Goroutine?

Goroutine 是 Go 中的轻量级线程,启动一个 Goroutine 比操作系统的线程开销小得多。你只需简单地在函数调用前加上一个 go 关键字,Go 就会帮你把这个函数放到独立的 Goroutine 中执行。Go程序可以同时跑成千上万的Goroutine,而不会像传统线程那样消耗大量资源。

启动 Goroutine

启动一个 Goroutine 非常简单,只需要在函数调用前加上 go 关键字:

package main

import (
	"fmt"
	"time"
)

func sayHello() {
	fmt.Println("Hello from Goroutine!")
}

func main() {
	go sayHello() // 启动一个 Goroutine
	time.Sleep(1 * time.Second) // 给 Goroutine 一些时间执行
	fmt.Println("Hello from main!")
}

在这个示例中,sayHello 函数在一个单独的 Goroutine 中运行,而主程序继续往下执行。在实际开发中,这种非阻塞的行为非常适合处理并发任务,比如处理多个请求或后台任务。

Goroutine 的生命周期

  • 启动:使用 go 启动一个 Goroutine,代码会立即并发执行。
  • 运行中:Goroutine 的运行是并发的,可能会与主程序或其他Goroutine同时执行。
  • 结束:当 Goroutine 的任务完成,或遇到 returnpanic 时,Goroutine 会自行结束。

一个很重要的点是,主程序(main Goroutine)退出时,所有其他 Goroutine 都会立刻停止。所以,你需要确保主 Goroutine 给予足够的时间让其他 Goroutine 完成任务。

2. 通道(Channel)

Goroutine 之间需要通过某种方式通信,Go为此设计了 通道(Channel),让你可以安全、简单地在线程间传递数据。通道就像是Goroutine之间的邮递员:一个Goroutine把数据通过通道送出去,另一个Goroutine可以通过通道把数据接收过来。

Channel 的基本用法:无缓冲和有缓冲

无缓冲通道

无缓冲通道的特点是:发送和接收必须同时发生,否则会导致发送方或接收方阻塞。

package main

import (
	"fmt"
)

func main() {
	ch := make(chan string)

	go func() {
		ch <- "Hello from Goroutine!" // 发送数据
	}()

	msg := <-ch // 接收数据
	fmt.Println(msg)
}

在这里,ch 是一个无缓冲的通道,Goroutine 通过 ch <- 向通道发送数据,主程序通过 <-ch 接收数据。

有缓冲通道

有缓冲通道允许你在通道中放置一定数量的值,而不需要立即被接收。

package main

import (
	"fmt"
)

func main() {
	ch := make(chan string, 2) // 创建一个带2个缓冲的通道

	ch <- "Message 1"
	ch <- "Message 2"

	fmt.Println(<-ch) // 输出: Message 1
	fmt.Println(<-ch) // 输出: Message 2
}

有缓冲通道就像一个“快递仓库”,可以暂时存储数据,等到合适的时候再接收。

Channel 的发送与接收

  • 发送数据:使用 <- 向通道发送数据:ch <- value
  • 接收数据:使用 <- 从通道接收数据:value := <-ch

select 语句

在Go中,select 语句允许你同时等待多个通道操作,是处理并发任务的利器。它有点像 switch,但专门用来处理通道的发送和接收。

package main

import (
	"fmt"
	"time"
)

func main() {
	ch1 := make(chan string)
	ch2 := make(chan string)

	go func() {
		time.Sleep(1 * time.Second)
		ch1 <- "First message"
	}()

	go func() {
		time.Sleep(2 * time.Second)
		ch2 <- "Second message"
	}()

	select {
	case msg1 := <-ch1:
		fmt.Println("Received:", msg1)
	case msg2 := <-ch2:
		fmt.Println("Received:", msg2)
	}
}

在这个例子中,select 会等待第一个收到数据的通道,并执行对应的代码块。它让你能够轻松地处理多个并发任务,而无需担心数据的竞争条件。

3. 并发模型:Go语言的CSP模型

Go语言的并发编程基于 CSP模型(Communicating Sequential Processes),即“通过通信实现并发”。Go通过 Goroutine 和 Channel 实现了这个模型,让多个 Goroutine 可以安全、清晰地通信和协作。

CSP模型的核心思想是:不要通过共享内存来通信,而是通过通信来共享内存。在Go中,Channel扮演了这种通信媒介的角色,简化了并发编程的复杂性。

4. 并发安全与 sync

在并发编程中,多个 Goroutine 同时读写同一个资源(比如变量)时,可能会出现数据竞态问题。Go提供了 sync 包中的一些工具来确保并发操作的安全。

sync.WaitGroup

sync.WaitGroup 允许主 Goroutine 等待其他 Goroutine 完成工作,非常适合协调多个并发任务。

package main

import (
	"fmt"
	"sync"
)

func worker(id int, wg *sync.WaitGroup) {
	defer wg.Done() // 完成任务后通知 WaitGroup
	fmt.Printf("Worker %d starting\n", id)
}

func main() {
	var wg sync.WaitGroup

	for i := 1; i <= 5; i++ {
		wg.Add(1) // 向 WaitGroup 注册一个 Goroutine
		go worker(i, &wg)
	}

	wg.Wait() // 等待所有注册的 Goroutine 完成
	fmt.Println("All workers done")
}

互斥锁(sync.Mutex)

sync.Mutex 是一种互斥锁,确保一次只有一个 Goroutine 能够访问某个共享资源。

package main

import (
	"fmt"
	"sync"
)

type Counter struct {
	mu    sync.Mutex
	value int
}

func (c *Counter) increment() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.value++
}

func main() {
	var wg sync.WaitGroup
	counter := Counter{}

	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < 1000; j++ {
				counter.increment()
			}
		}()
	}

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

sync.Mutex 确保每次只有一个 Goroutine 能够执行 increment 函数,避免了竞态条件。

原子操作(sync/atomic)

sync/atomic 提供了更底层的原子操作来处理并发问题,比如增加或减少一个整数而不需要加锁。

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

func main() {
	var counter int64
	var wg sync.WaitGroup

	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < 1000; j++ {
				atomic.AddInt64(&counter, 1)
			}
		}()
	}

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

使用 atomic 可以避免锁的开销,并确保并发安全。

结论

Go语言的并发编程模型让处理并发任务变得既简单又高效。通过 Goroutine 和 Channel,你可以轻松地启动并管理多个任务,并使用 sync 包中的工具确保数据的并发安全。在实际开发中,Go的并发机制尤其适用于高并发服务、后台任务处理等场景。

希望通过这篇博客,你对Go语言的并发编程有了更深入的理解。记住,Goroutine 和 Channel 是你在Go世界中穿梭的秘密武器,让你的程序在多任务处理上如虎添翼!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32外设之SPI的介绍

### STM32外设之SPI的介绍 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;主要用于EEPROM、FLASH、实时时钟、AD转换器等外设的通信。SPI通信只需要四根线&#xff0c;节约了芯片的管脚&#x…

浅谈语言模型推理框架 vLLM 0.6.0性能优化

在此前的大模型技术实践中&#xff0c;我们介绍了加速并行框架Accelerate、DeepSpeed及Megatron-LM。得益于这些框架的助力&#xff0c;大模型的分布式训练得以化繁为简。 然而&#xff0c;企业又该如何将训练完成的模型实际应用部署&#xff0c;持续优化服务吞吐性能&#xf…

初始 html

html 文件结构 html 标签是整个 html 文件的根标签(最顶层标签) head 标签中写页面的属性. body 标签中写的是页面上显示的内容 title 标签中写的是页面的标题 <html><head><title>这是一个标题</title></head><body></body> <…

springboot校园支付系统-计算机毕业设计源码36348

目 录 摘要 Abstract 1 绪论 1.1 研究背景与意义 1.2 开发技术和开发特点 1.3论文结构与章节安排 2 校园支付系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.…

The First项目报告:抗 MEV 交易的CoW Protocol什么?

2023年&#xff0c;当UNIswap推出UniswapX 时&#xff0c;市场迎接它的不是赞叹&#xff0c;而是一片争议。UniswapX被指抄袭 CoWSwap 和 1inch。Curve 官方称 1inch 和 CoWSwap 早已改变游戏规则&#xff0c;UniswapX 非首创。CoWSwap 强调其 Intent Based Trading 的先驱地位…

【Linux系列】 环境配置文件合并的艺术:从`.env`到`.env.combined`

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Fastadmin框架短视频系统视频知识付费源码

简介&#xff1a; FastAdmin框架短视频系统/视频知识付费源码/附带小说系统 系统视频支持包月、单独购买、观影卷等功能 源码附带小说系统 源码需要配置高服务器和VDN加速 图片&#xff1a; 下载地址&#xff1a;云盘下载 原文地址&#xff1a;Fastadmin框架短视频系统视…

计算机体系结构之多级缓存、缓存miss及缓存hit(二)

前面章节《计算机体系结构之缓存机制原理及其应用&#xff08;一&#xff09;》讲了关于缓存机制的原理及其应用&#xff0c;其中提出了多级缓存、缓存miss以及缓存hit的疑问。故&#xff0c;本章将进行展开讲解&#xff0c; 多级缓存、缓存miss以及缓存hit存在的意义是为了保持…

后端SpringBoot学习项目-用户管理-增删改查

最终代码结构 仓库地址 Entity文件 数据库表设计 entity层实现 文件创建 ● 创建entity文件夹 ● 在entity层创建Java类&#xff0c;名字为User (关键字不可使用) 代码实现 package com.example.drhtspringboot.entity;import com.baomidou.mybatisplus.annotation.IdT…

华为入围Linux 内核CVE 检视“五人团”,openEuler要再进阶?

背景&#xff1a;内核社区接管 Linux 社区漏洞发布 往年 Linux 内核漏洞发布存在来源不固定、覆盖不全面&#xff0c;有时发布无修复补丁的 CVE 从而形成 0-day 漏洞等问题&#xff0c;给 Linux 内核安全带来了不确定性&#xff0c;为了更规范化运作&#xff0c;2024 年 2 月 1…

【C语言指南】C语言内存管理 深度解析

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C语言指南》 期待您的关注 引言 C语言是一种强大而灵活的编程语言&#xff0c;为程序员提供了对内存的直接控制能力。这种对内存…

12 Node.js API接口开发

八、API接口 8.1 json-server工具 1&#xff09;安装json-server npm i -g json-server2)示例 //students.json {"student":[{"id":1,"name":"sally","age":18,"gender":"女"},{"id":2,&…

前段时间我所在的公司收到了来自Nevicat的律师函

前段时间我所在的公司收到了来自Nevicat的律师函&#xff0c;至于原因嘛&#xff0c;大家懂的都懂。肯定是因为没有购买人家的正版软件&#xff0c;于是公司下令&#xff0c;所有人禁止继续使用Nevicat自行寻找其他sql工具&#xff0c;迫于无奈&#xff0c;在我使用了十几款主流…

【系统设计】理解带宽延迟积(BDP)、吞吐量、延时(RTT)与TCP发送窗口的关系:优化网络性能的关键

在设计和优化网络性能时&#xff0c;理解 带宽延迟积&#xff08;BDP&#xff09;、吞吐量、延时&#xff08;RTT&#xff09; 和 TCP发送窗口 之间的关系至关重要。这些概念相互影响&#xff0c;决定了网络连接的性能上限&#xff0c;尤其是在高带宽、高延迟的环境中&#xff…

微服务容器化部署实践(FontConfiguration.getVersion)

文章目录 前言一、整体步骤简介二、开始实战1.准备好微服务2.将各个微服务打包为镜像第一种第二种3. 将各个打包好的镜像,通过docker-compose容器编排,运行即可总结前言 docker容器化部署微服务: 将微服务容器化部署到 Docker 容器中是一个常见的做法,可以提高应用的可移…

如何监控员工上网行为?五大妙招轻松上手,员工上网监控全攻略!挖到宝啦!

如何监控员工上网行为&#xff1f; 员工的不当上网行为不仅有可能导致企业机密的泄露&#xff0c;还可能对工作效率造成显著影响。 因此&#xff0c;如何有效地监控员工的上网行为&#xff0c;已成为许多企业管理者关注的重点。 本文&#xff0c;将为您介绍五大妙招&#xff…

【C++ 算法进阶】算法提升十一 十二

目录标题 让字符串成为回文串的最少插入次数题目题目分析代码题目题目 字符子串 &#xff08;滑动窗口&#xff09;题目题目分析代码 最长连续子序列 &#xff08;头尾表&#xff09;题目题目分析代码 让字符串成为回文串的最少插入次数 题目 本题为为LC原题 题目如下 题目分…

Linux(CentOS)安装 MySQL

CentOS版本&#xff1a;CentOS 7 三种安装方式&#xff1a; 一、通过 yum 安装&#xff0c;最简单&#xff0c;一键安装&#xff0c;全程无忧。 二、通过 rpm 包安装&#xff0c;需具备基础概念及常规操作。 三、通过 gz 包安装&#xff0c;需具备配置相关操作。 --------…

6.1 软件测试:软件质量与测试

软件质量与测试 1、软价质量保证1.1 软件质量质量控制QC&#xff1a;QUALITY CONTROL质量保证QA:QUALITY ASSURANCE质量成本软件质量软件质量保证 1.2 软件评审1.3 软件可靠性 2、软件测试2.1 软件测试过程模型软件测试策略软件测试策略V模型回归测试软件测试策略原则软件测试策…

JavaEE进阶---SpringMVC(二)请求里面十种参数类型

文章目录 1.请求1.1接受单个参数的请求1.2多个参数的传递1.3传递对象1.4参数重命名1.5设置参数是非必传的1.6数组的请求方式1.7如何传递集合1.8传递json数据1.9获取url里面的参数1.10获取文件 1.请求 1.1接受单个参数的请求 下面的这个就是我们的项目代码&#xff0c;都是单个…