Go实现并发与并行,这才是正确打开方式!

简介: Go实现并发与并行,这才是正确打开方式!

并发(Concurrency)与并行(Parallelism)是两个容易混淆的概念。本文将阐明两者的内涵、实现机制、应用场景、优劣势等方面的区别。

1、并发是什么

并发是一种处理多任务的能力,它意味着程序可以同时处理多段指令流,但是执行顺序未必确定,也不要求同时执行。

例如一个 Web 服务器,可以同时处理请求 A、请求 B,但是执行顺序由系统调度,A 和 B 不一定同时执行。

Go 语言使用 Goroutine 实现并发,Goroutine 是轻量级线程,由 Go 运行时(Runtime)负责调度


func server() {  go handleRequestA()  go handleRequestB()}

Goroutine 具有启动迅速、资源消耗少的优点,非常适合大规模并发。

2、并行是什么

并行则要求同时执行多道指令,真正做到同时进行,以提高程序执行速度。并行依赖多核 CPU。

Go 语言可以检测 CPU 核数量,将任务并行分配给每个核心执行



func main() {  cpu := runtime.NumCPU()
  var wg sync.WaitGroup  wg.Add(cpu)  for i := 0; i < cpu; i++ {    go func() {      defer wg.Done()      // 并行执行任务    }()  }
  wg.Wait() // 等待所有任务结束}

这样就实现了真正的并行计算。另外,GPU 带来了更强大的并行计算能力,可用于深度学习等场景。

3、并发与并行的区别

并发与并行存在一些关键区别:

并发强调同时处理多任务,而并行强调同时执行多任务。

并发使用线程、Goroutine 实现,并行使用多核心实现。

并发关注任务处理能力,并行关注执行速度。

简单来说:

并发是处理,并行是执行。

并发可以通过线程等实现,并行依赖多核。

4


// 并发下载多个URLfunc download(urls []string) {  ch := make(chan string)  for _, url := range urls {    go func(url string) {      resp := downloadUrl(url)      ch <- resp // 返回结果    }(url)  }    for range urls {    <-ch // 获取结果  }}

上面的示例使用 Goroutine 实现了并发下载任务,然后通过 Channel 获取每个下载的结果。

这里强调的是处理多任务的能力,而不是同时执行下载。

5

func calculate(matrix [][]float32) [][]float32 {  cpu := runtime.NumCPU()  chs := make([]chan []float32, cpu)    // 并行计算   for i:= 0; i< cpu; i++ {    ch := make(chan []float32)    go func(m [][]float32, ch chan []float32) {      ch <- parallelCalc(m)    }(matrix, ch)    chs[i] = ch  }
  // 合并结果  result := make([][]float32, 0)  for _, ch := range chs {    item := <-ch    result = append(result, item)  }
  return result}

这里根据 CPU 数量,将矩阵任务并行分配给每个核心处理,然后合并结果,真正达到了并行计算的效果。

6、并发的优点

相比并行,并发更难实现,但其主要优点是:

更快响应用户交互请求

更好地利用系统资源

代码逻辑组织更合理

显示进度及状态更方便

Go 并发编程可以大大提升服务器响应效率。

7、并行的优点

并行编程的优势在于:

极大提升计算吞吐量

更快完成计算密集型任务

更高的运算效率

使得并行非常适合科学计算、数据分析等场景。

8、总结

并发强调同时处理多任务,并行强调同时执行

并发使用线程等机制,并行利用多核实现

并发偏重任务量,并行注重执行速度

两者在一定程度上可以联用,发挥各自优势

Go 语言很好地支持了并发和并行。理解两者的区别和各自应用场景,可以设计出更合理、高效的程序。

目录
相关文章
|
5天前
|
人工智能 Go 调度
掌握Go并发:Go语言并发编程深度解析
掌握Go并发:Go语言并发编程深度解析
|
5天前
|
安全 Java Go
Java vs. Go:并发之争
【4月更文挑战第20天】
25 1
|
5天前
|
Go 调度 开发者
CSP模型与Goroutine调度的协同作用:构建高效并发的Go语言世界
【2月更文挑战第17天】在Go语言的并发编程中,CSP模型与Goroutine调度机制相互协同,共同构建了高效并发的运行环境。CSP模型通过通道(channel)实现了进程间的通信与同步,而Goroutine调度机制则确保了并发任务的合理调度与执行。本文将深入探讨CSP模型与Goroutine调度的协同作用,分析它们如何共同促进Go语言并发性能的提升。
|
5天前
|
存储 算法 编译器
掌握Go语言:探索Go语言递归函数的高级奥秘,优化性能、实现并发、解决算法难题(28)
掌握Go语言:探索Go语言递归函数的高级奥秘,优化性能、实现并发、解决算法难题(28)
|
5天前
|
SQL Go 数据库
【Go语言专栏】Go语言中的事务处理与并发控制
【4月更文挑战第30天】Go语言在数据库编程中支持事务处理和并发控制,确保ACID属性和多用户环境下的数据完整性。`database/sql`包提供事务管理,如示例所示,通过`Begin()`、`Commit()`和`Rollback()`执行和控制事务。并发控制利用Mutex、WaitGroup和Channel防止数据冲突。结合事务与并发控制,开发者可处理复杂场景,实现高效、可靠的数据库应用。
|
5天前
|
Cloud Native Go 云计算
多范式编程语言Go:并发与静态类型的结合
Go语言是Google于2007年开发的开源编程语言,旨在提高程序开发和部署的效率。它的独特特征在于结合了并发处理与静态类型系统,提供了简洁、高效、并行处理能力的编程体验。本文将探讨Go语言的特点、应用场景以及其在现代软件开发中的优势。
|
5天前
|
安全 Go
Golang深入浅出之-Go语言中的并发安全队列:实现与应用
【5月更文挑战第3天】本文探讨了Go语言中的并发安全队列,它是构建高性能并发系统的基础。文章介绍了两种实现方法:1) 使用`sync.Mutex`保护的简单队列,通过加锁解锁确保数据一致性;2) 使用通道(Channel)实现无锁队列,天生并发安全。同时,文中列举了并发编程中常见的死锁、数据竞争和通道阻塞问题,并给出了避免这些问题的策略,如明确锁边界、使用带缓冲通道、优雅处理关闭以及利用Go标准库。
26 5
|
5天前
|
存储 缓存 安全
Golang深入浅出之-Go语言中的并发安全容器:sync.Map与sync.Pool
Go语言中的`sync.Map`和`sync.Pool`是并发安全的容器。`sync.Map`提供并发安全的键值对存储,适合快速读取和少写入的情况。注意不要直接遍历Map,应使用`Range`方法。`sync.Pool`是对象池,用于缓存可重用对象,减少内存分配。使用时需注意对象生命周期管理和容量控制。在多goroutine环境下,这两个容器能提高性能和稳定性,但需根据场景谨慎使用,避免不当操作导致的问题。
35 4
|
5天前
|
安全 Go 开发者
Golang深入浅出之-Go语言中的CSP模型:深入理解并发哲学
【5月更文挑战第2天】Go语言的并发编程基于CSP模型,强调通过通信共享内存。核心概念是goroutines(轻量级线程)和channels(用于goroutines间安全数据传输)。常见问题包括数据竞争、死锁和goroutine管理。避免策略包括使用同步原语、复用channel和控制并发。示例展示了如何使用channel和`sync.WaitGroup`避免死锁。理解并发原则和正确应用CSP模型是编写高效安全并发程序的关键。
35 4
|
5天前
|
安全 Go 开发者
Golang深入浅出之-Go语言中的CSP模型:深入理解并发哲学
【5月更文挑战第1天】Go语言基于CSP理论,借助goroutines和channels实现独特的并发模型。Goroutine是轻量级线程,通过`go`关键字启动,而channels提供安全的通信机制。文章讨论了数据竞争、死锁和goroutine泄漏等问题及其避免方法,并提供了一个生产者消费者模型的代码示例。理解CSP和妥善处理并发问题对于编写高效、可靠的Go程序至关重要。
26 2