理解 goroutine 的并发

本文详细探讨了Go语言中的goroutine,从预备知识、goroutine的并发特性到编程准则,揭示了goroutine的本质。 goroutine并非线程,而是轻量级的并发执行单元,具有低开销和高效的特点。文章强调了goroutine编程的基本准则,包括友好线程调度、关注资源竞争,并介绍了如何构建消息驱动的goroutine。同时,文章提供了并发模式的实践指导,如生成器、服务化、多路复合等,旨在帮助开发者更好地理解和运用goroutine进行并发编程。
摘要由CSDN通过智能技术生成

理解 goroutine 的并发

线程(Thread)对于语言的重要性不言而喻,每个语言都要“发明”自己最高效的线程库以说明自己的厉害,go 也不能免俗的。但 Go 语言却不认为自己是线程,叫 goroutine? Why? 本文通过案例加深对goroutine 的本质理解,在此基础上介绍 goroutine 编程涉及的内容以及四个编程准则。

如果你只是使用 goroutine,直接将 goroutine 理解为轻量级的线程,配合 chan 做通讯,足以应付多数工程项目。如果你要做线程池、或控制 goroutine ,例如 kill,stop,resume 等典型的线程操作,那你就的深入理解 goroutine 的并发,也需要你具备更多 OS 的知识。 本文会告诉你 kill 等想法是不实际的。

用一个不太确当的比喻,有一个病人得了阑尾炎,你作为医生可能会有如下选择:

  • 合格的医学博士(MD):手术前,给出“手术知情通知”
  • 会开刀,但不太了解各种后果:手术前,给出“病危通知”
  • 不会开刀:给出一个保守治疗方案,让病人自己调理

你可能期望自己选择第一项,但你必须经过严格、长时间的教育和训练。go 的理念是简单,选择的第三项。这合理吗? 答案是合理!

就线程来说,kill 一个线程的需求是似乎“合理”的。但是 java 的 API 在后面的版本也取消了它(但可用),因为强制线程退出会导致涉及资源的锁异常,导致后续程序难以正常获取资源,除非你能控制所有可能的后果。 go 设计者应该这样思考,既然一般程序员不能控制 kill 线程的后果,与其让它产生不确定后果,不如给个简单、高效、安全的 API。

一、预备知识

1.1 进程、线程、协程

进程(Process):在内存中的程序。有自己独立的独占的虚拟 CPU 、虚拟的 Memory、虚拟的 IO devices。

OS 直接支持并调度。进程之间只能通过系统提供的 IO 机制通讯。共享内存(变量)是不可能的!

  • (1) 每一进程占用独立的地址空间。
    • 此处的地址空间包括代码、数据及其他资源。
  • (2) 进程间的通信开销较大且受到许多限制。
    • 对象(或函数)接口、通信协议、…
  • (3) 进程间的切换开销也较大。
    • 又称Context Switch。
    • 上下文包括代码、数据、堆栈、处理器状态、资源、…

线程(Thread):轻量级进程。在现代操作系统中,是进程中程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。

一个进程由若干线程组成,它们共享进程的计算、存储、IO资源。因此,程序员必须使用系统提供的同步、消息机制,处理资源的竞争和消息的通讯。

  • (1) 多个线程共享进程的地址空间(代码、数据、其他资源等)。
    • 线程也需要自己的资源,如程序计数器、寄存器组、调用栈等。
  • (2) 线程间的通信开销较少且比较简单。
    • 因为共享而减少了需要通信的内容。
    • 但也因为充分共享而无法对共享资源进行保护。
  • (3) 线程间的切换开销也较小。
    • 只需保存每一线程的程序计数器、寄存器组、堆栈等空间。
    • 不必切换或复制整个地址空间,从而成本大为降低(约1/10)

线程有分为两大类:

  • 操作系统管理的线程(Core Thread),通常根据 CPU 资源决定线程的数量,一般为 CPU 数量的两倍。
  • 语言提供的线程库管理的线程(User Thread),它执行时映射到系统线程,按任务类型(计算密集型,IO密集型)决定线程池的管理方式与数量。

协程(coroutine/fiber):轻量级线程。 是可以并发执行的函数,由编译或用户指定位置将控制权交给协程调度程序执行的方式。它是非抢占式的,可以避免反复系统调用,还有进程切换造成的开销,给你上几千个逻辑流,也称用户级别线程。

在单线程模式下,协程不需要自己上下文,可以大大减少资源竞争的情况。例如,读写map的项时,不需要锁整个表。在 JavaScript、python等单进程单线程、数据驱动(流式)的应用中,协程比线程更有效率;结合回调函数,更高效的处理 IO 请求。

https://www.zhihu.com/question/20511233

1.2 绿色线程(green thread)

知道这个名词的 java 程序员,一定不一般的。一句话就是可管理、可移植的用户线程。

二、“失控” 的 goroutine

启动一个 goroutine 仅需要 go func(...) 就 OK 了。Go 的表达这个函数是并发执行的,反正这之后它的命运只能由 runtime 库

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值