Go新手步步为赢:并发编程通信指南

简介: Go新手步步为赢:并发编程通信指南

概述

Go 语言在并发通信方面有着独特的 CSP 并发模型。

Go 语言主要通过 Channel 实现 Goroutine 间通信,也支持共享内存和原子操作方式。

本文将通过示例阐述 Go 语言的各种并发通信方式。

主要内容包括

并发通信机制

Channel 通信详解

共享内存通信

原子操作通信

通信方式选用指南

Channel 通信示例


 

一、并发通信机制

Go 语言支持以下三种 Goroutine 间通信方式:

Channel 通信:Goroutine 间传递消息和数据

共享内存:通过内存共享指定数据

原子操作:利用原子操作的同步效应

每种方式都有明确的使用场景,应根据具体需求选择合适的通信方式。


 

二、Channel 通信详解

Channel 是 Go 语言内置的 goroutine 间同步通信机制。可以通过 Channel 在多个 goroutine 间传递消息或数据。

1. 创建方式

使用 make 创建 Channel



ch := make(chan int) //无缓冲区Channelch := make(chan int, 100) //有缓冲Channel

2. 数据传输

通过操作符<-向 Channel 发送或接收数据



ch <- 10 // 发送数据到Channelx := <- ch // 从Channel接收数据

3. 关闭 Channel

可以通过内置 close 函数关闭 Channel


close(ch)

4. 选择器

可以通过 select 选择多个 Channel 的通信


select {  case <-ch1:    // 操作ch1  case <-ch2:      // 操作ch2  default:    // 默认操作}

5. 常见通信方式

Channel 支持多种通信方式:

同步返回值

发布-订阅

工作池


 

三、共享内存通信

Go 程序也可以通过共享内存进行通信:

1.

// Counter包
var Value int // 共享变量
func SetValue(v int) {  Value = v // 写入共享变量 } 
func ReadValue() int {  return Value // 读取共享变量}

2. 并发安全数据结构

Go 标准库提供了许多并发安全的数据结构,如 sync.Map


var sMap sync.Map
sMap.Store("key", value) // 写入数据v, _ := sMap.Load("key") // 读取数据

这类数据结构利用内部锁保证并发安全。

3. 自定义共享数据

可以通过内置原子函数从零开始构建共享数据


type atomicInt struct {  val int32}
func (a *atomicInt) Increase() {  atomic.AddInt32(&a.val, 1)}
func (a *atomicInt) Value() int32 {  return atomic.LoadInt32(&a.val) }


 

四、原子操作通信

Go 语言提供了原子操作函数,可以被用来进行原子通信


import "sync/atomic"
var flag int32 
func wait() {  for atomic.LoadInt32(&flag) == 0 {     runtime.Gosched()  }}
func notify() {  atomic.StoreInt32(&flag, 1) }

利用原子操作的同步效应实现 Goroutine 间通知等待。

原子函数列表:

atomic.SwapInt32

atomic.CompareAndSwapInt32

atomic.AddInt32

atomic.LoadInt32

atomic.StoreInt32


 

五、通信方式选用指南

不同的通信方式各有优劣:

Channel

天然同步机制

编译期检测

只适合短小消息

共享内存

适合任意数据

必须使用同步原语

存在竞争风险

原子操作

最低层次通信

必须自己实现同步逻辑

可构建高级通信方式

根据具体场景需求,比如性能、频率、数量、分布式等方面来选择最合适的通信方式。


 

六、Channel 通信示例

1.

func worker(in, out chan *Task) {  for {    t := <-in    // 处理t    out<- t  }}
func CreateWorkerPool(num int) {  in := make(chan *Task)   out := make(chan *Task)
  // 启动goroutine  for i:= 0; i < num; i++ {     go worker(in, out)   }
  return in, out}

2.

type Hub struct {  subs map[chan<- int]bool}
func (h *Hub) subscribe() chan<- int {  ch := make(chan int)  h.subs[ch] = true  return ch}
func (h *Hub) broadcast(msg int) {  for sub := range h.subs {    sub <- msg  }}


 

总结

Go 语言内置了丰富的通信方式,包括 Channel、共享内存和原子操作,每种方式都有明确的应用场景

Channel 在不同 Goroutine 间传递消息和数据,它是 Go 的默认选择。

共享内存可以在 Goroutine 间直接共享数据,但需要控制并发访问。

原子操作提供了最底层的通信方式,需要自己实现同步逻辑。

选择合适的通信方式很重要,需要根据具体问题的并发模式、性能需求、数据量等方面进行决策。

充分理解和运用这些通信机制,可以设计出简洁高效的 Go 语言并发程序。

目录
相关文章
|
18天前
|
Go 调度 开发者
Go语言中的并发编程:深入理解与实践###
探索Go语言在并发编程中的独特优势,揭秘其高效实现的底层机制。本文通过实例和分析,引导读者从基础到进阶,掌握Goroutines、Channels等核心概念,提升并发处理能力。 ###
|
3月前
|
缓存 NoSQL Go
通过 SingleFlight 模式学习 Go 并发编程
通过 SingleFlight 模式学习 Go 并发编程
|
2天前
|
存储 设计模式 安全
Go语言中的并发编程:从入门到精通###
本文深入探讨了Go语言中并发编程的核心概念与实践技巧,旨在帮助读者从理论到实战全面掌握Go的并发机制。不同于传统的技术文章摘要,本部分将通过一系列生动的案例和代码示例,直观展示Go语言如何优雅地处理并发任务,提升程序性能与响应速度。无论你是Go语言初学者还是有一定经验的开发者,都能在本文中找到实用的知识与灵感。 ###
|
7天前
|
Serverless Go
Go语言中的并发编程:从入门到精通
本文将深入探讨Go语言中并发编程的核心概念和实践,包括goroutine、channel以及sync包等。通过实例演示如何利用这些工具实现高效的并发处理,同时避免常见的陷阱和错误。
|
7天前
|
安全 Go 开发者
代码之美:Go语言并发编程的优雅实现与案例分析
【10月更文挑战第28天】Go语言自2009年发布以来,凭借简洁的语法、高效的性能和原生的并发支持,赢得了众多开发者的青睐。本文通过两个案例,分别展示了如何使用goroutine和channel实现并发下载网页和构建并发Web服务器,深入探讨了Go语言并发编程的优雅实现。
20 2
|
9天前
|
Go 调度 开发者
Go语言的并发编程模型
【10月更文挑战第26天】Go语言的并发编程模型
8 1
|
14天前
|
安全 Go 调度
Go语言中的并发编程:解锁高性能程序设计之门####
探索Go语言如何以简洁高效的并发模型,重新定义现代软件开发的边界。本文将深入剖析Goroutines与Channels的工作原理,揭秘它们为何成为实现高并发、高性能应用的关键。跟随我们的旅程,从基础概念到实战技巧,一步步揭开Go并发编程的神秘面纱,让您的代码在多核时代翩翩起舞。 ####
|
16天前
|
存储 Go 开发者
Go语言中的并发编程与通道机制
本文将探讨Go语言中并发编程的核心概念——goroutine和通道(channel)。我们将从基础开始,解释什么是goroutine以及如何创建和使用它们。然后,我们将深入探讨通道的概念、类型以及如何使用通道在goroutine之间进行通信。最后,我们将通过一个示例来展示如何在实际应用中使用goroutine和通道来实现并发编程。
|
5月前
|
Go
go语言并发编程(五) ——Context
go语言并发编程(五) ——Context
|
21天前
|
Go 开发者
Go语言中的并发编程:从基础到实践
在当今的软件开发中,并发编程已经成为了一项不可或缺的技能。Go语言以其简洁的语法和强大的并发支持,成为了开发者们的首选。本文将带你深入了解Go语言中的并发编程,从基础概念到实际应用,帮助你掌握这一重要的编程技能。
下一篇
无影云桌面