go原生并发原语和最佳实践(代码片段)

Go语言中文网 Go语言中文网     2022-11-28     269

关键词:

Go 编程语言是用并发作为一等公民创建的。它是一种语言,通过抽象出语言中并发原语1背后的并行性细节,您可以轻松编写高度并行的程序。

大多数语言都将并行化作为标准库的一部分,或者期望开发者生态系统提供并行化库。通过在 Go 语言中包含并发原语,你可以编写并行性的程序,而无需了解编写并行代码的来龙去脉。

原语与论文中对原语的描述非常相似,实际上这来自 Rob Pike 之前基于 CSP 构建语言的工作。

在 Pike 的一次演讲中,他将真正的问题确定为“需要一种方法来编写并发软件,以指导我们的设计和实现。”他接着说并发编程不是让程序并行化以更快地运行,而是“利用流程和通信的力量来设计优雅、响应迅速、可靠的系统。”

包或任何阻塞函数。
  • 此代码仅使用 Go 并发原语 go,selectchan
  • 共享资源的所有权由 goroutine 管理。(第 17 行)
  • 即使该方法包含一个 goroutine,对共享资源的访问也不会并行发生。(第 30 和 34 行)
  • select 语句用于检查读取或写入请求。(第 24 和 34 行)
  • 从 incoming 会更新该值。(第 24 行)
  • 从 goroutine 外部读取的通道使用共享资源的当前值执行对 outgoing 写入。(第 34 行)
  • 由于单个 goroutine 本身没有并行性,因此可以通过返回的只读通道安全地访问共享资源 。事实上,select 这里使用该语句提供了许多好处。选择原语部分对此进行了更详细的介绍。

    原语创建的 goroutine 很轻量,但重要的是要知道它们不是免费的。清理 goroutine 对于确保在 Go 运行时中正确收集资源非常重要。

    应该花时间在设计上考虑清理。确保长时间运行的 goroutine 在发生故障时正确退出。同样重要的是不要创建无数的 goroutine。

    生成一个 goroutine 很简单,因此很容易无节制的生成新的 goroutine,生成的每个 goroutine 的最小开销约为 2kb。如果你的代码创建了太多 goroutine,并且每个 goroutine 都有很大的开销,那么栈空间可能不够。这在生产环境中调试起来非常困难,因为很难判断堆栈在哪里溢出以及堆栈在哪里泄漏。

    当发生堆栈溢出时,运行时将 panic,程序将退出,每个 goroutine 都会将堆栈信息打印到标准错误。这会在日志中产生大量噪音并且不是很有用。不仅堆栈信息没有用,而且还会输出大量数据(每个 goroutine 的日志,包括它的标识符和状态)。这也很难调试,因为通常操作系统上的日志缓冲区可能太小而无法容纳所有堆栈信息。

    注意:公平地说,我只在应用程序使用超过 400,000 个大型 goroutine 的生产环境中看到这种情况。这可能很少见,对于大多数应用程序来说都不是问题。

    TL;DR:设计 goroutines 时要考虑到最终结果,以便它们在完成时正确停止。

    一个 nil 通道总是堵塞

    实现。

    有时可能无法关闭通道,因为它会在应用程序的其他地方引起 panic(即往关闭的通道写入)。在这种情况下,当通道超出作用范围时,它将被垃圾收集。

       只读 channel 不能关闭

    通常,仅在真的需要时才使用缓冲通道。最佳实践是使用无缓冲通道。

    后面的箭头表示数据流流出通道。

    只读通道的一个示例是time.Tick 函数:

      传递给函数 NewTime并用于指示 goroutine 停止。tchan 通道是普通的无缓冲通道,但以只读方式返回。

    当传递给内部 goroutine 时,tchan通道作为只写通道传递。因为内部 goroutine 提供了一个只写通道,所以它有责任在完成时关闭通道。

    使用 select 语句,time.Now() 调用仅在从通道读取时执行。这确保time.Now() 调用的执行与从通道读取同步。这种类型的模式有助于抢先减少 CPU 周期。

    使用此模式,你无法检测from通道何时关闭。这意味着from通道将不断地向 to 通道发送数据,并且内部 goroutine 将永远不会退出,从而导致大量零值数据和 goroutine 泄漏。

    根据你的使用场景,这可能是可取的,但是,重要的是要注意,当你需要检测关闭的通道时,这种模式不是一个好方式。

    语句允许在 Go 应用程序中管理多个通道,并可用于触发操作、管理数据或以其他方式创建逻辑并发流。

    本质上是随机的。这意味着如果有多个通道准备好同时读取或写入,该select语句将随机选择一个 case 语句来执行。

    方法返回的只读通道返回时退出 。

      是 context,并且应该命名为 ctx

    原文链接:https://benjiv.com/go-native-concurrency-primitives/。


    推荐阅读

  • Go 中实现用户的每日限额(比如一天只能领三次福利)

  • 福利

    我为大家整理了一份从入门到进阶的Go学习资料礼包,包含学习建议:入门看什么,进阶看什么。关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。

    图解go并发(代码片段)

    ...强大的社区支持。学习这门语言最令人兴奋的一点是它的并发模型。Go的并发原语使创建多线程并发程序变得简单而有趣。我将通过插图介绍Go的并发原语,希望能点透相关概念以方便后续学习。本文是写给Go语言编程新手以及准... 查看详情

    云原生时代崛起的编程语言go并发编程实战(代码片段)

    ...o代码示例认识Go的协程、通道、定时器、互斥锁、池化、原生操作等十几个并发编程示例,进一步加深对其并发编程使用场景理解和原理的初步认识。@目录概述基础理论并发原语协程-Goroutine通道-Channel多路复用-Select通道使用超... 查看详情

    golang基础:底层并发原语mutexrwmutexcondwaitgrouponce等使用和基本实现(代码片段)

    ...量Cond等待组WaitGroup仅执行一次Once原子操作其他上一篇《原生并发goroutinechannel和select常见使用场景》介绍了基于CSP模型的并发方式。除了CSP,Go通过sync包以及atomic包还提供了一些更底层的同步API,一般用于性能要求比较... 查看详情

    golang基础:底层并发原语mutexrwmutexcondwaitgrouponce等使用和基本实现(代码片段)

    ...量Cond等待组WaitGroup仅执行一次Once原子操作其他上一篇《原生并发goroutinechannel和select常见使用场景》介绍了基于CSP模型的并发方式。除了CSP,Go通过sync包以及atomic包还提供了一些更底层的同步API,一般用于性能要求比较... 查看详情

    golang基础:底层并发原语mutexrwmutexcondwaitgrouponce等使用和基本实现(代码片段)

    ...量Cond等待组WaitGroup仅执行一次Once原子操作其他上一篇《原生并发goroutinechannel和select常见使用场景》介绍了基于CSP模型的并发方式。除了CSP,Go通过sync包以及atomic包还提供了一些更底层的同步API,一般用于性能要求比较... 查看详情

    golang基础:底层并发原语mutexrwmutexcondwaitgrouponce等使用和基本实现(代码片段)

    ...量Cond等待组WaitGroup仅执行一次Once原子操作其他上一篇《原生并发goroutinechannel和select常见使用场景》介绍了基于CSP模型的并发方式。除了CSP,Go通过sync包以及atomic包还提供了一些更底层的同步API,一般用于性能要求比较... 查看详情

    java并发编程实战-创建和执行任务的最佳实践(代码片段)

    若无法通过并行流实现并发,则必须创建并运行自己的任务。运行任务的理想Java8方法就是CompletableFuture。Java并发的历史始于非常原始和有问题的机制,并且充满各种尝试的优化。本文将展示一个规范形式,表示创建... 查看详情

    一文带你进行go语言工程实践(代码片段)

    文章目录并发和Goroutine并发和并行的区别线程与协程的区别Goroutine用法并发的通信Channel并发安全依赖管理GOPATHGOPATH弊端GoVendorGoVendor弊端GoModule(最终解决方案依赖管理三要素配置文件版本规则杂项中心仓库管理依赖库依赖的... 查看详情

    爆肝3天只为golang错误处理最佳实践(代码片段)

    对于开发者来说,要是不爽Go错误处理,那就看看最佳实践。Go可能引入trycatch吗?那可能估计有点难度。本文简单介绍Go为什么选择这样的错误处理和目前常见处理方式,并梳理常见Go错误处理痛点,给出最佳... 查看详情

    爆肝3天只为golang错误处理最佳实践(代码片段)

    对于开发者来说,要是不爽Go错误处理,那就看看最佳实践。Go可能引入trycatch吗?那可能估计有点难度。本文简单介绍Go为什么选择这样的错误处理和目前常见处理方式,并梳理常见Go错误处理痛点,给出最佳... 查看详情

    go并发实践(代码片段)

    Go并发实践废话不多说,先来几行代检验下你是否适合本文,如果你发现看不懂建议先去看看简单点的东西。gof()gof("abc",123)ch:=make(chanint)gofunc()c<-123()fmt.Println(<-ch)简单的例子ok,下面假设这样一个场景,有... 查看详情

    go语言实践(代码片段)

    本文由Austin发表指导原则我们要谈论在一个编程语言中的最佳实践,那么我们首先应该明确什么是“最佳”。如果您们听了我昨天那场讲演的话,您一定看到了来自Go团队的RussCox讲的一句话:软件工程,是您在编程过程中增加了... 查看详情

    go语言实践(代码片段)

    本文由Austin发表指导原则我们要谈论在一个编程语言中的最佳实践,那么我们首先应该明确什么是“最佳”。如果您们听了我昨天那场讲演的话,您一定看到了来自Go团队的RussCox讲的一句话:软件工程,是您在编程过程中增加了... 查看详情

    并发编程实践之公平有界阻塞队列实现(代码片段)

    ...编程的利器。本文讲述在没有JUC工具包帮助下,借助原生的JAVA同步原语,如何实现一个公平有界的阻塞队列。希望你也能在文后体会到并发编程的复杂之处,以及JUC工具包的强。作者|李新然来源|阿里技术公众号一背景JUC... 查看详情

    go36-34,35-并发安全字典(sync.map)(代码片段)

    ...。这篇要讲的是一个并发安全的高级数据结构:sync.Map。原生字典Go语言自带的字典类型map,就是原生字典,并不是并发安全的。在使用原生字典的时候,应该在启动goroutine之前就完成字典的初始化和赋值。或者更高级的做法是... 查看详情

    基于go/grpc/kubernetes/istio开发微服务的最佳实践尝试(代码片段)

    基于Go/Grpc/kubernetes/Istio开发微服务的最佳实践尝试-1/3基于Go/Grpc/kubernetes/Istio开发微服务的最佳实践尝试-2/3基于Go/Grpc/kubernetes/Istio开发微服务的最佳实践尝试-3/3项目地址:https://github.com/janrs-io/Jgrpc转载请注明来源:https://janrs.com/... 查看详情

    go语言并发编程(代码片段)

    ...能超过1万个。这也是协程也叫轻量级线程的原因。golang原生支持并发编程轻量级线程非抢占式多任务处理,由协程主动交出控制权编译器/解释器/虚拟机层面的多任务多个协程可能在一个或多个线程上运行1.1go对协程的实现gorouti... 查看详情

    go中的错误和异常处理最佳实践

    本文已收录​​编程学习笔记​​。涵盖PHP、JavaScript、Linux、Golang、MySQL、Redis和开源工具等等相关内容。错误认识错误在Go中,错误是一种表示程序错误状态。包含了在程序在运行时、编译时的状态信息。一般我们在编写Go代码... 查看详情