【Go入门】并发
【Go入门】并发
有人把Go比作21世纪的C语言,第一是因为Go语言设计简单,第二,21世纪最重要的就是并行程序设计,而Go从语言层面就支持了并行。
goroutine
goroutine是Go并行设计的核心。goroutine说到底其实就是协程,但是它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。
goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过go
关键字实现了,其实就是一个普通的函数。
go hello(a, b, c)
通过关键字go就启动了一个goroutine。我们来看一个例子
package mainimport ("fmt""runtime"
)func say(s string) {for i := 0; i < 5; i++ {runtime.Gosched()fmt.Println(s)}
}func main() {go say("world") //开一个新的Goroutines执行say("hello") //当前Goroutines执行
}// 以上程序执行后将输出:
// hello
// world
// hello
// world
// hello
// world
// hello
// world
// hello
我们可以看到go关键字很方便的就实现了并发编程。
上面的多个goroutine运行在同一个进程里面,共享内存数据,不过设计上我们要遵循:不要通过共享来通信,而要通过通信来共享。
runtime.Gosched()表示让CPU把时间片让给别人,下次某个时候继续恢复执行该goroutine。
默认情况下,在Go 1.5将标识并发系统线程个数的runtime.GOMAXPROCS的初始值由1改为了运行环境的CPU核数。
但在Go 1.5以前调度器仅使用单线程,也就是说只实现了并发。想要发挥多核处理器的并行,需要在我们的程序中显式调用 runtime.GOMAXPROCS(n) 告诉调度器同时使用多个线程。GOMAXPROCS 设置了同时运行逻辑代码的系统线程的最大数量,并返回之前的设置。如果n < 1,不会改变当前设置。
channels
goroutine运行在相同的地址空间,因此访问共享内存必须做好同步。那么goroutine之间如何进行数据的通信呢,Go提供了一个很好的通信机制channel。channel可以与Unix shell 中的双向管道做类比:可以通过它发送或者接收值。这些值只能是特定的类型:channel类型。定义一个channel时,也需要定义发送到channel的值的类型。注意,必须使用make 创建channel:
ci := make(chan int)
cs := make(chan string)
cf := make(chan interface{})
channel通过操作符<-
来接收和发送数据
ch <- v // 发送v到channel ch.
v := <-ch // 从ch中接收数据,并赋值给v
我们把这些应用到我们的例子中来:
package mainimport "fmt"func sum(a []int, c chan int) {total := 0for _, v := range a {total += v}c <- total // send total to c
}func main() {a := []int{7, 2, 8, -9, 4, 0}c := make(chan int)go sum(a[:len(a)/2], c)go sum(a[len(a)/2:], c)x, y := <-c, <-c // receive from cfmt.Println(x, y, x + y)
}
默认情况下,channel接收和发送数据都是阻塞的,除非另一端已经准备好,这样就使得Goroutines同步变的更加的简单,而不需要显式的lock。所谓阻塞,也就是如果读取(value := <-ch)它将会被阻塞,直到有数据接收。其次,任何发送(ch<-5)将会被阻塞,直到数据被读出。无缓冲channel是在多个goroutine之间同步很棒的工具。
Buffered Channels
上面我们介绍了默认的非缓存类型的channel,不过Go也允许指定channel的缓冲大小,很简单,就是channel可以存储多少元素。ch:= make(chan bool, 4),创建了可以存储4个元素的bool 型channel。在这个channel 中,前4个元素可以无阻塞的写入。当写入第5个元素时,代码将会阻塞,直到其他goroutine从channel 中读取一些元素,腾出空间。
ch := make(chan type, value)
当 value = 0 时,channel 是无缓冲阻塞读写的,当value > 0 时,channel 有缓冲、是非阻塞的,直到写满 value 个元素才阻塞写入。
我们看一下下面这个例子,你可以在自己本机测试一下,修改相应的value值
package mainimport "fmt"func main() {c := make(chan int, 2)//修改2为1就报错,修改2为3可以正常运行c <- 1c <- 2fmt.Println(<-c)fmt.Println(<-c)
}//修改为1报如下的错误://fatal error: all goroutines are asleep - deadlock!
Range和Close
上面这个例子中,我们需要读取两次c,这样不是很方便,Go考虑到了这一点,所以也可以通过range,像操作slice或者map一样操作缓存类型的channel,请看下面的例子
package mainimport ("fmt"
)func fibonacci(n int, c chan int) {x, y := 1, 1for i := 0; i < n; i++ {c <- xx, y = y, x + y}close(c)
}func main() {c := make(chan int, 10)go fibonacci(cap(c), c)for i := range c {fmt.Println(i)}
}
for i := range c
能够不断的读取channel里面的数据,直到该channel被显式的关闭。上面代码我们看到可以显式的关闭channel,生产者通过内置函数close
关闭channel。关闭channel之后就无法再发送任何数据了,在消费方可以通过语法v, ok := <-ch
测试channel是否被关闭。如果ok返回false,那么说明channel已经没有任何数据并且已经被关闭。
记住应该在生产者的地方关闭channel,而不是消费的地方去关闭它,这样容易引起panic
另外记住一点的就是channel不像文件之类的,不需要经常去关闭,只有当你确实没有任何发送数据了,或者你想显式的结束range循环之类的
Select
我们上面介绍的都是只有一个channel的情况,那么如果存在多个channel的时候,我们该如何操作呢,Go里面提供了一个关键字select
,通过select
可以监听channel上的数据流动。
select
默认是阻塞的,只有当监听的channel中有发送或接收可以进行时才会运行,当多个channel都准备好的时候,select是随机的选择一个执行的。
package mainimport "fmt"func fibonacci(c, quit chan int) {x, y := 1, 1for {select {case c <- x:x, y = y, x + ycase <-quit:fmt.Println("quit")return}}
}func main() {c := make(chan int)quit := make(chan int)go func() {for i := 0; i < 10; i++ {fmt.Println(<-c)}quit <- 0}()fibonacci(c, quit)
}
在select
里面还有default语法,select
其实就是类似switch的功能,default就是当监听的channel都没有准备好的时候,默认执行的(select不再阻塞等待channel)。
select {
case i := <-c:// use i
default:// 当c阻塞的时候执行这里
}
超时
有时候会出现goroutine阻塞的情况,那么我们如何避免整个程序进入阻塞的情况呢?我们可以利用select来设置超时,通过如下的方式实现:
func main() {c := make(chan int)o := make(chan bool)go func() {for {select {case v := <- c:println(v)case <- time.After(5 * time.Second):println("timeout")o <- truebreak}}}()<- o
}
runtime goroutine
runtime包中有几个处理goroutine的函数:
-
Goexit
退出当前执行的goroutine,但是defer函数还会继续调用
-
Gosched
让出当前goroutine的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行。
-
NumCPU
返回 CPU 核数量
-
NumGoroutine
返回正在执行和排队的任务总数
-
GOMAXPROCS
用来设置可以并行计算的CPU核数的最大值,并返回之前的值。
相关文章:

【Go入门】并发
【Go入门】并发 有人把Go比作21世纪的C语言,第一是因为Go语言设计简单,第二,21世纪最重要的就是并行程序设计,而Go从语言层面就支持了并行。 goroutine goroutine是Go并行设计的核心。goroutine说到底其实就是协程,…...

Java虚拟机运行时数据区结构详解
Java虚拟机运行时数据区结构如图所示 程序计数器 程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。 多线程切换时,为了能恢复到正确的执行位置,每条线程…...

华为OD机试 - 转盘寿司(Java JS Python C)
目录 题目描述 输入描述 输出描述 用例 题目解析 JS算法源码 Java算法源码...

【ATTCK】MITRE Caldera-emu插件
CALDERA是一个由python语言编写的红蓝对抗工具(攻击模拟工具)。它是MITRE公司发起的一个研究项目,该工具的攻击流程是建立在ATT&CK攻击行为模型和知识库之上的,能够较真实地APT攻击行为模式。 通过CALDERA工具,安全…...

23111709[含文档+PPT+源码等]计算机毕业设计基于Spring Boot智能无人仓库管理-进销存储
文章目录 **软件开发环境及开发工具:****功能介绍:****论文截图:****数据库:****实现:****代码片段:** 编程技术交流、源码分享、模板分享、网课教程 🐧裙:776871563 软件开发环境及…...

SDUT OJ《算法分析与设计》贪心算法
A - 汽车加油问题 Description 一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。并证明算法能产生一个最优解。 对于给定的n和k个加油站位置,计算最少加油次数。 I…...

金融业务系统: Service Mesh用于安全微服务集成
随着云计算的不断演进,微服务架构变得日益复杂。为了有效地管理这种复杂性,人们开始采用服务网格。在本文中,我们将解释什么是Service Mesh,为什么它对现代云架构至关重要,以及它是如何解决开发人员今天面临的一些最紧…...

Linux下快速确定目标服务器支持哪些协议和密码套件
实现原理是利用TLS协议的特点和握手过程来进行测试和解析响应来确定目标服务器支持哪些TLS协议和密码套件。 在TLS握手过程中,客户端和服务器会协商并使用相同的TLS协议版本和密码套件来进行通信。通过发送特定的握手请求并分析响应,可以确定目标服务器…...

LeetCode100122. Separate Black and White Balls
文章目录 一、题目二、题解 一、题目 There are n balls on a table, each ball has a color black or white. You are given a 0-indexed binary string s of length n, where 1 and 0 represent black and white balls, respectively. In each step, you can choose two a…...

系列二十六、idea安装javap -c
一、概述 javap -c是一个能够将.java文件反编译为.class文件的指令,例如我在idea中编写了一个Car.java文件,我想看看这个类被编译后长什么样的,就可以使用该指令进行查看。 二、配置 2.1、 Java Bytecode Decompiler File>Settings>Pl…...

nginx 如何根据IP做限流,以及 nginx 直接返回 json 格式数据
Nginx 限流配置 Nginx是如何限流的。随着业务的扩散,系统并发越来越高时,有三样利器用来保护系统,分别是缓存、降级和限流。 随着业务的扩散,系统并发越来越高时,有三样利器用来保护系统,分别是缓存、降…...

C语言链式栈
stack.h typedef struct Node_s {int data;struct Node_s *pNext; } Node_t, *pNode_t;typedef struct Stack_s {pNode_t pHead;//栈顶指针,指向了链表的第一个结点int size;//栈的元素个数 } Stack_t, *pStack_t;void init(pStack_t pStack); void push(pStack_t …...

【Go入门】 Go的http包详解
【Go入门】 Go的http包详解 前面小节介绍了Go怎么样实现了Web工作模式的一个流程,这一小节,我们将详细地解剖一下http包,看它到底是怎样实现整个过程的。 Go的http有两个核心功能:Conn、ServeMux Conn的goroutine 与我们一般编…...

解决k8s node节点报错: Failed to watch *v1.Secret: unknown
现象: 这个现象是发生在k8s集群证书过期,重新续签证书以后。 记得master节点的/etc/kubernetes/kubelet.conf文件已经复制到node节点了。 但是为什么还是报这个错,然后运行证书检查命令看一下: 看样子是差/etc/kubernetes/pki/…...

日志维护库:loguru
在复杂的项目中,了解程序的运行状态变得至关重要。在这个过程中,日志记录(logging)成为我们追踪、调试和了解代码执行的不可或缺的工具。在python语言中常用logging日志库,但是logging日志库使用相对繁琐,在…...

【Go入门】 Go如何使得Web工作
【Go入门】 Go如何使得Web工作 前面小节介绍了如何通过Go搭建一个Web服务,我们可以看到简单应用一个net/http包就方便的搭建起来了。那么Go在底层到底是怎么做的呢?万变不离其宗,Go的Web服务工作也离不开我们第一小节介绍的Web工作方式。 w…...

汽车虚拟仿真视频数据理解--CLIP模型原理
CLIP模型原理 CLIP的全称是Contrastive Language-Image Pre-Training,中文是对比语言-图像预训练,是一个预训练模型,简称为CLIP。该模型是 OpenAI 在 2021 年发布的,最初用于匹配图像和文本的预训练神经网络模型,这个任…...

【Web】Ctfshow SSTI刷题记录1
目录 ①web361 362-无过滤 ②web363-过滤单双引号 ③web364-过滤单双引号和args ④web365-过滤中括号[]、单双引号、args ⑤web366-过滤单双引号、args、中括号[]、下划线 ⑦web367-过滤单双引号、args、中括号[]、下划线、os ⑧web368-过滤单双引号、args、中括号[]、下…...

【广州华锐互动】VR可视化政务服务为公众提供更直观、形象的政策解读
虚拟现实(VR)技术正在逐渐应用于政务服务领域,为公众提供更加便捷、高效和个性化的服务体验。通过VR眼镜、手机等设备,公众可以在虚拟环境中参观政务服务中心,并根据自己的需求选择不同的办事窗口或事项进行咨询和办理…...

音视频项目—基于FFmpeg和SDL的音视频播放器解析(七)
介绍 在本系列,我打算花大篇幅讲解我的 gitee 项目音视频播放器,在这个项目,您可以学到音视频解封装,解码,SDL渲染相关的知识。您对源代码感兴趣的话,请查看基于FFmpeg和SDL的音视频播放器 如果您不理解本…...

Sql Server 2017主从配置之:发布订阅
使用发布订阅模式搭建Sql Server 2017主从同步,类似事件通知机制,基本可以做到准实时同步,可以同时做到一对多的数据同步。 不过发布订阅模式,只能同时数据,不能同步表结构。在创建发布的时候,需要选择需要…...

聊聊logback的EvaluatorFilter
序 本文主要研究一下logback的EvaluatorFilter EvaluatorFilter ch/qos/logback/core/filter/EvaluatorFilter.java public class EvaluatorFilter<E> extends AbstractMatcherFilter<E> {EventEvaluator<E> evaluator;Overridepublic void start() {if …...

解决vue 部分页面缓存,部分页面不缓存的问题
前端时间项目迭代,其中有个需求 在vue里面,有a.b.c三个页面,要达到的效果是从a页面进去b页面,b页面需要刷新,但若从b页面进入c页面了以后再回到b页面,b页面需要保留之前的值,不做刷新࿱…...

修完这个 Bug 后,MySQL 性能提升了 300%
最近 MySQL 官方在 8.0.35 上修复了一个 bug: 这个 bug 是由 Mark Callaghan 发现的。Mark 早年在 Google MySQL 团队,后来去了 Meta MySQL,也主导了 RocksDB 的开发。 Mark 在 #109595 的 bug report 给出了非常详细的复现步骤 在官方修复后…...

【C/PTA】数组进阶练习(二)
本文结合PTA专项练习带领读者掌握数组,刷题为主注释为辅,在代码中理解思路,其它不做过多叙述。 目录 7-1 字符串逆序7-2 字符串替换7-3 统计字符出现次数7-4 IP地址转换7-1 删除重复字符7-2 说反话-加强版7-3 数组-回文串7-4 数组-无聊的菇菇…...

Mysql MMM
MMM概述 MMM(Master-Master replication manager for MvSQL,MySQL主主复制管理器) 是一套支持双主故障切换和双主日常管理的脚本程序。 MMM 使用 Perl 语言开发,主要用来监控和管理MySQL Master-Master(双主)复制&…...

GDPU 数据结构 天码行空10
目录 数据结构实验十 树遍历应用一、【实验目的】二、【实验内容】三、【实验源代码】⭐ CPP版⭐ c语言版 四、实验结果 数据结构实验十 树遍历应用 一、【实验目的】 1、了解树的建立方法 2、掌握树与二叉树的转化及其遍历的基本方法 3、掌握递归二叉树遍历算法的应用 二、…...

CD36 ; + Lectin;
CD2 LIMP-2, LGP85 SR-BI, CD36; 清道夫受体蛋白CD36超家族的成员是 脂质代谢 和 先天免疫 的重要调节因子。它们识别正常和修饰的脂蛋白,以及与病原体相关的分子模式。 该家族由三个成员组成: SR-BI &am…...

Git 分支管理
目录 列出分支 删除分支 分支合并 合并冲突 几乎每一种版本控制系统都以某种形式支持分支,一个分支代表一条独立的开发线。 使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。 Git 分支实际上是指向更改快照的指针。 有…...

Vue23全局事件总线
Vue2&3全局事件总线 Vue2全局事件总线 功能:可以解决所有组件之间通信传数据的问题原理:通过一个共享对象,将所有组件全部绑定到对象上,即可通过这个对象实现组件与组件之间的传递数据,而这个共享对象叫做全局事件…...