Go-并发模式1(Basic Examples)

简介: Go-并发模式1(Basic Examples)

一个无聊的函数

package main
import (
  "fmt"
  "time"
)
func main() {
  boring("boring!")
}
func boring(msg string) {
  for i := 0; ; i++ {
    fmt.Println(msg, i)
    time.Sleep(time.Second)
  }
}

过一秒输出一下boring! 加数字,结果如下:

2020062310470442.png

稍微无聊的函数

package main
import (
  "fmt"
  "math/rand"
  "time"
)
func main() {
  boring("boring!")
}
// START OMIT
func boring(msg string) {
  for i := 0; ; i++ {
    fmt.Println(msg, i)
    time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
  }
}

不再等待一个固定的时间

2020062310470442.png

使用goroutine

package main
import (
  "fmt"
  "math/rand"
  "time"
)
func main() {
  go boring("boring!")
}
func boring(msg string) {
  for i := 0; ; i++ {
    fmt.Println(msg, i)
    time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
  }
}

我们在main函数中使用goroutine来运行go函数,结果

2020062310470442.png

是的,没有错,直接结束了程序,因为在go中不会默认等待goroutine结束

使用goroutine并等待一段时间

package main
import (
  "fmt"
  "math/rand"
  "time"
)
func main() {
  go boring("boring!")
  fmt.Println("I'm listening.")
  time.Sleep(2 * time.Second)
  fmt.Println("You're boring; I'm leaving.")
}
func boring(msg string) {
  for i := 0; ; i++ {
    fmt.Println(msg, i)
    time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
  }
}

在main函数中等待了2秒,然后结束

2020062310470442.png

什么是goroutine呢?

goroutine是独立运行的函数。它有自己的调用栈,不是线程,可能成千上万个goroutine只有一个线程,根据需要将goroutine动态地多路复用到线程上,以保持所有goroutine的运行。

通信

前面的例子给了大家一个假象,仿佛知道goroutine在运行什么,输出什么。但实际上,我们无法得知goroutine应该运行多长时间。因此,我们需要通信来进行更好的程序衔接与合作,这就引出了channel。

使用通道channels

package main
import (
  "fmt"
  "math/rand"
  "time"
)
func main() {
  c := make(chan string)
  go boring("boring!", c)
  for i := 0; i < 5; i++ {
    fmt.Printf("You say: %q\n", <-c) // Receive expression is just a value.
  }
  fmt.Println("You're boring; I'm leaving.")
}
func boring(msg string, c chan string) {
  for i := 0; ; i++ {
    c <- fmt.Sprintf("%s %d", msg, i) // Expression to be sent can be any suitable value.
    time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
  }
}

使用channel进行通信,goroutine的函数一直向channel中放数据,main中从channel获取

同步

当主函数执行<–c时,它将等待发送值。

类似地,当boring函数执行c<–value时,它会等待接收者准备就绪。

发送方和接收方都必须准备好在通信中发挥作用。

因此,通道既通信又同步。Go 通过交流来分享数据,而不是通过分享数据来交流!

2020062310470442.png

至此,和现实生产有点像了。

channel可以有buffer,类似e-mail,这里不会涉及。

参考

Google IO 2012 Go Concurrency Patterns

b站中文字幕版

PPT

全部代码

更多Go相关内容:Go-Golang学习总结笔记

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。


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