其实从一开始了解到go的goroutine概念就应该想到,其实go应该就是在内核级线程的基础上做了一层逻辑上的虚拟线程(用户级线程)+ 线程调度系统,如此分析以后,goroutine也就不再那么神秘了。
并发≠并行
假如我们有一段CPU密集型任务,我们创建2000个gorountine是否真的可以将其性能提高2000倍,答案必然是不能,因为我们只是进行了2000次的并发(concurrency),而并没有真正做到并行(parallelism)。
并发其实所指的是我们的程序执行逻辑,传统单线程应用的程序逻辑是顺序执行的,在任何时刻,程序只能处理同一个逻辑,而并发指的是,我们同时执行多个独立的程序逻辑,若干个程序逻辑在执行时可以是同时进行的(但并不代表同时进行处理)。实际上,不论我们并发多少个程序逻辑,若我们仅仅将其运行在一个单核单线程的CPU上,都不能让你的程序在性能上有所提升,因为最终所有任务都排队等待CPU资源(时间片)。
而并行才能让我们的程序真正的同时处理多个任务,但并行并不是编程语言能够带我们的特性,他需要硬件支持。上面说到单核CPU所有资源都要等待同一个CPU的资源,那么其实我们只要将CPU增多就能真正的让我们实现并行。我们可以使用多核CPU或用多台服务器组成服务集群,均可实现真正的并行,能够并行处理的任务数量也就是我们的CPU数量。
引用Rob Pikie大神在PPT《Concurrency is not Parallelism》中的一段总结,大意就是并发不同于并行,但并发也许可以让程序实现并行化。
Concurrency vs. parallelism
Concurrency is about dealing with lots of things at once.
Parallelism is about doing lots of things at once.
Not the same, but related.
Concurrency is about structure, parallelism is about execution.
Concurrency provides a way to structure a solution to solve a problem that may (but not necessarily) be parallelizable.
CPU密集&I/O密集
那么是不是说我们在单核CPU的机器上使用编程语言所提供的多线程就没有意义了呢?
如果说我们的程序属于CPU密集型,使用并发编程,可能确实无法提升我们的程序性能,甚至可能因为大量计算资源花在了创建线程本身,导致程序性能进一步下降。
但不同的是,如果说我们的程序属于IO密集型,当你在进行程序压测的过程中可能发现CPU占用率很低,但性能却到了瓶颈,原因是程序将大量的时间花在了等待IO的过程中,如果我们可以在等待IO的时候继续执行其他的程序逻辑即可提高CPU利用率,从而提高我们的程序性能,这时并发编程的好处就出来了,例如Python因为GIL的存在实际上并不能实现真正的并行,但他的多线程依旧在IO密集型的程序中依旧有种很重要的意义。
Goroutine(Golang Coroutine)
上面说到了使用多核CPU实现并行处理,使应用在多核cpu实现并行处理的方案主要是多进程与多线程两种方式,多进程模型相对简单,但是有着资源开销大及进程间通信成本高的问题。多线程模型相对复杂,会有死锁,线程安全,模型复杂等问题,但却因为资源开销及易于管理等优点适用于对于性能要求较高的应用。
Golang采用的是多线程模型,更详细的说他是一个两级线程模型,但它对系统线程(内核级线程)进行了封装,暴露了一个轻量级的协程goroutine(用户级线程)供用户使用,而用户级线程到内核级线程的调度由golang的runtime负责,调度逻辑对外透明。
goroutine的优势在于上下文切换在完全用户态进行,无需像线程一样频繁在用户态与内核态之间切换,节约了资源消耗。
同时,启动一个gorountine非常简单,而且写法很cool~
go function()
仅仅需要在调用函数时在前面加上关键字go即可创建一个goroutine并创建其上下文对象。
G·P·M
G(Goroutine) :我们所说的协程,为用户级的轻量级线程,每个Goroutine对象中的sched保存着其上下文信息
M(Machine) :对内核级线程的封装,数量对应真实的CPU数(真正干活的对象)
P(Processor) :即为G和M的调度对象,用来调度G和M之间的关联关系,其数量可通过GOMAXPROCS()来设置,默认为核心数
每个Processor对象都拥有一个LRQ(Local Run Queue),未分配的Goroutine对象保存在GRQ(Global Run Queue )中,等待分配给某一个P的LRQ中,每个LRQ里面包含若干个用户创建的Goroutine对象,同时Processor作为桥梁对Machine和Goroutine进行了解耦,也就是说Goroutine如果想要使用Machine需要绑定一个Processor才行,上图*有两个M和两个P也就是说我们可以同时并行处理两个goroutine。
这一篇主要讲解了一些并行与并发的区别Golang并发模型的优势,下一篇会详细说明GPM模型的调度策略。
Golang并发原理及GPM调度策略(一)的更多相关文章
-
golang并发编程
golang并发编程 引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止go ...
-
马蜂窝搜索基于 Golang 并发代理的一次架构升级
搜索业务是马蜂窝流量分发的重要入口.很多用户在使用马蜂窝时,都会有目的性地主动搜索与自己旅行需求相关的各种信息,衣食住行,事无巨细,从而做出最符合需求的旅行决策. 因此在马蜂窝,搜索业务交互的下游模块 ...
-
Golang 并发简介
并发概要 随着多核CPU的普及, 为了更快的处理任务, 出现了各种并发编程的模型, 主要有以下几种: 模型名称 优点 缺点 多进程 简单, 隔离性好, 进程间几乎无影响 开销最大 多线程 目前使用最多 ...
-
golang 并发顺序输出数字
参考 package main import ( "fmt" "sync/atomic" "time" ) func main() { va ...
-
Golang - 并发编程
目录 Golang - 并发编程 1. 并行和并发 2. go语言并发优势 3. goroutine是什么 4. 创建goroutine 5. runtime包 6. channel是什么 7. ch ...
-
MySQL InnoDB 实现高并发原理
MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...
-
golang 并发demo 写入 redis
原文链接:golang 并发demo 写入 redis 源代码: package main import ( "fmt" "runtime" "str ...
-
4种Golang并发操作中常见的死锁情形
摘要:什么是死锁,在Go的协程里面死锁通常就是永久阻塞了,你拿着我的东西,要我先给你然后再给我,我拿着你的东西又让你先给我,不然就不给你.我俩都这么想,这事就解决不了了. 本文分享自华为云社区< ...
-
Golang并发模型之Context详解
对于 Golang 开发者来说context(上下文)包一定不会陌生.但很多时候,我们懒惰的只是见过它,或能起到什么作用,并不会去深究它. 应用场景:在 Go http 包的 Server 中,每一个 ...
随机推荐
-
angular源码分析:$compile服务——指令的编写
这一期中,我不会分析源码,只是翻译一下"https://docs.angularjs.org/api/ng/service/$compile",当然不是逐字逐句翻译,讲解指令应该如 ...
-
UISegmentedControl
1. NSArray *segmentedArray = [[NSArray alloc]initWithObjects:@"1",@"2",@"3& ...
-
C#.Net 图片处理大全
C# How to: Image filtering by directly manipulating Pixel ARGB values C# How to: Image filtering imp ...
-
valgrind 内存检测与调用图生成
http://blog.csdn.net/destina/article/details/6198443 感谢作者的分享! 一 valgrind是什么? Valgrind是一套Linux下,开放源 ...
-
mysql之7xtrabackup
目录: 1.前言 2.环境 3.开始备份 3.1.innobackupex介绍 3.2.一次完全备份 3.3.一次完全恢复 3.4.增量备份 3.5.增量备份的恢复过程 1.前言: Xtrabacku ...
-
Problem A
Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum ...
-
2019.03.25 bzoj4539: [Hnoi2016]树(主席树+倍增)
传送门 题意:给一棵大树,令一棵模板树与这棵树相同,然后进行mmm次操作,每次选择模板树中的一个节点aaa和大树中一个节点bbb,把aaa这棵子树接在bbb上面,节点编号顺序跟aaa中的编号顺序相同. ...
-
jfinal头像裁剪上传服务器
前端页面完整代码,复制可用,记得导入库文件 <!DOCTYPE html> <html lang="en"> <head> <title& ...
-
CCCatmullRomBy和CCPointArray
CCCatmullRomBy:把某一对象以Catmull-Rom curve曲线移动一段距离 CCPointArray *array = CCPointArray::create(); array-& ...
-
接口(interface)那点事
1.接口(interface),在 java中有这个类型哦,这是语法哦. public interface MyInterface { } 语法还是很清晰的哦, 类的关键字是class.而接口改为in ...