31|并发:Go的并发方案实现方案是怎样的?
该思维导图由 AI 生成,仅供参考
什么是并发?
- 深入了解
- 翻译
- 解释
- 总结
Go语言通过goroutine、channel和select等语法特性实现了原生支持并发的设计目标。传统编程语言在并发设计上存在诸多不足,如复杂的线程管理、通信困难等问题。相比之下,Go语言的并发方案具有轻量级、通信简单、自动扩展等特点,通过原生支持并发的设计,解决了传统编程语言的诸多问题,为开发者提供了更加便捷、高效的并发编程体验。 Go语言的并发方案主要体现在goroutine和channel的使用上。goroutine作为Go原生支持并发的一个具体实现,具有独立的代码执行流,并与创建它的goroutine一起被Go运行时调度。而channel作为goroutine间的通信原语,为并发设计提供了强大支撑。Go语言借鉴了CSP并发模型,通过channel将goroutine组合连接在一起,让设计和编写大型并发系统变得更加简单和清晰。 总的来说,Go语言通过原生支持并发的设计,解决了传统编程语言在并发方面的诸多问题,为开发者提供了更加便捷、高效的并发编程体验。文章通过介绍并发与并行的区别、传统编程语言在并发设计上的不足之处以及Go语言的并发实现方案,强调了Go语言的改进之处,为读者提供了对Go语言并发方案的全面了解。
《Tony Bai · Go 语言第一课》,新⼈⾸单¥59
全部留言(19)
- 最新
- 精选
- pythonbug老师好,有个问题想不大清楚:当main里面有go func的时候,是会将go func 放到另外一个处理器执行;还是说当前处理器先执行go func,然后一段时间后回来继续执行main,这样切换来切换去的。
作者回复: 第一, goroutine是轻量级线程(G),它被调度到执行器M上执行,而不是cpu上。M会被os调度到cpu上执行。 第二,可运行的G先被放入P的队列,每个P绑定一个可以用于执行G的M。之后调度程序可以从P队列中取出G放在M上执行。一个G执行一定时间后,再从队列中取出另一个G运行。 基于上述描述,你的问题,当main中通过go func启动一个新goroutine后,就会有两个可运行的(runnable)的G,新G会被放入P的队列并等待被调度。至于新G是否会与原先的main G分配到一个P上,不确定。如果机器只有一个cpu core。那么显然就如你所说的,新G与main G轮流被调度执行。如果有多个cpu core,那么新G与main G可能就是并行(paralell)执行的。
2022-04-28223 - lesserror大白老师很擅长将复杂的知识深入浅出的讲解出来,这是很多教程没有做到的。读了这一篇,对于Go的并发设计有了新的认识,意犹未尽。另有两处模糊的地方: 1. 文中的 P-n、P-m,这里的n和m应该没有特别的含义吧? 就是指代一个Process而已吧? 2. 文中说:“比如涉及性能敏感的区域或需要保护的结构体数据时”,这里的:结构体数据,应该就是Go的 struct 吧?
作者回复: 1. 对,n,m只是序号。 2.对。通常我们用struct来抽象事物。保护的也是通常也是这种类型数据。
2022-01-0812 - 路边的猪有个问题请教下各位。 func main() { ctx, cancel := context.WithCancel(context.Background()) go func() { defer func() { fmt.Println("goroutine exit") }() for { select { case <-ctx.Done(): return default: time.Sleep(time.Second) } } }() time.Sleep(time.Second) cancel() time.Sleep(2 * time.Second) } 最近看并发原语这块。一个使用场景是通过cancelContext 来中止一个 执行慢业务的groutine。 有个问题不解,通过select 语句 监听两个 case 。 其中一个case 用于监听 ctx取消的,然后返回终止当前groutine执行。另一个case 用户执行慢业务逻辑。 这里问题是,这个监听的动作需要不停的去for循环 检查ctx.Done ,但是真正的慢业务 会阻塞 select啊。也就检查不到 ctx.Done啊,还怎么起到 通过ctx 控制取消慢业务groutine的作用呢? 比如这里的default语句 如果里面的业务不是睡眠1秒而是发起了一个网络调用需要很久,那即使 下面cancel() 被调用 select语句中依然会被阻塞在 网络调用里。
作者回复: 好问题! 我的理解是:那就需要那个慢业务调用本身也支持Context。很多人说context.Context有“传染”效应,大概就是这个意思。
2022-06-1646 - Junior Programmer也想请问一下老师,能不能顺便讲解一下,同步和异步的概念
作者回复: 同步与异步的概念应用很广,在很多领域都有应用。比如通信领域,比如并发编程领域。 这一讲的同步设计中的“同步(sync)”指的是并发编程中对临界区进行“互斥”访问的概念,即有且仅有一个goroutine可以进入临界区,操作临界区的数据。其他goroutine只能在临界区外“排队”等待时机进入。 不过无论用在那个领域,“同步”与“异步”的通用含义是: 同步操作:执行流 只有等待发起的同步操作完成后,才能继续向下执行。 异步操作:发起异步操作后,原执行流可以无需等待,即可向下继续执行。
2022-06-126 - 罗杰作为一个开发者,还是要尽早了解并发和并行的区别,这节课要好好的学习和理解。
作者回复: 👍
2022-01-086 - 左耳朵东可不可以这样理解:输入输出原语应用在函数上就是函数签名(参数、返回值),应用到 goroutine 之间就是 channel。具体一点,在函数场景想要输入马上想到通过参数传入,想要输出通过返回值给;在 goroutine 之间,想要输入则马上想到通过 channel 拿,想要把处理结果输出,放到 channel 中就行了。
作者回复: 有点这个意思。
2022-11-04归属地:北京5 - Junior Programmer读了这节课,让我清晰认识到之前的的一个误区,就是并发和并行的区别。并发:针对的是程序结构设计,将一个程序分成若干个模块,不同模块单独执行,由多个模块相互交替执行,实现程序的运行。并行:针对的程序的执行,指的是同一时间点,有个多个任务在被多个或者多核的CPU下调度执行。
作者回复: 👍
2022-06-1234 - 阿星func spawn(f func() error) <-chan error { c := make(chan error) go func() { c <- f() }() return c } func main() { c := spawn(func() error { time.Sleep(2 * time.Second) return errors.New("timeout") }) fmt.Println("hello,world1") fmt.Println(<-c) fmt.Println("hello,world2") } 通过对上面的代码测试后我的理解是这样的: spawn中的 go func() 是异步执行(可能与主线程是并行), 所以在主线程中的spawn不会阻塞,先打印出了 "hello,world1", 等到打印 <-c 的时候就阻塞了,等从c 中读出数据打印结束后才会继续执行后续的打印 "hello,world2"。 所以说从channel 中读取数据可以认为肯定是一个阻塞的同步数据操作,不知道我的理解对吗?
作者回复: ✅👍。
2023-01-23归属地:四川3 - aoeCSP、响应式编程简介: CSP(Communicationing Sequential Processes,通信顺序进程)并发模型 响应式编程或反应式编程(英语:Reactive programming)是一种面向数据流和变化传播的声明式编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。 CSP、响应式编程两者的思想非常像(以我目前的理解没看出区别),但是使用Java、Scala之类的语言实现响应式编程一般需要借助额外的框架编程(例如 Reactor)。 但使用 Go 编程居然是语言自带的特性,一个关键字 go 就行了!
作者回复: 👍
2022-01-113 - 菠萝吹雪—Code这节讲的太好了,并发和并行理解透了
作者回复: 👍
2022-09-06归属地:北京2