详解golang GMP(一)

最近在研究go语言中,高性能缓存的实现,发现需要考虑到很多因素。(go语言中groupcache缓存库的源码解析可以看这一篇golang中cache组件的使用之groupcache(三)
这片文章主要讲解 golang 中的GMP。

开篇

提到GMP, 我们需要从最基础的进程、线程讲起。
网络上有很多进程线程的文章,本篇另辟蹊径,用故事举例的方式帮助大家理解。
本篇文章有不当之处希望大家可以指出。

进程、线程

并发与并行

大家都知道,在特定场景下(比如向1w台服务器发送指令),使用多线程或多进程会提升执行效率,那么提升效率的原因是什么呢?
简单点来说, 一个线程(或进程)相当于一个人。假设我们现在需要种树,多个人在工具(锹、铲子)足够的情况下,肯定会比一个人快,但是人多了容易把活干乱,这时就需要一个指挥者

那么,线程(或进程)相当于人, 刚才说的工具和指挥者相当于什么呢?
没错, 就是`cpu核心`和`调度器`。
在常见操作系统中,线程才是cpu真正的调度单位。进程中至少会包含一个线程。

我们现在的电脑或者服务器,都是多核心的。
上文举了工人工具的例子,帮助大家简单了解。那么更细致一点呢?
我们考虑下面的这种情况:

  • 工人有两个, 但是工具只有一个。老板是个好心人,不忍心赶走多余工人

老板思前想后, 多余的工人该怎么办呢?
有了,工人总需要吃饭、上厕所,一个去吃饭、上厕所,另一个顶上;或者两班倒,一个睡觉了,另一个干活。这样不就不会浪费了么。

这里的`吃饭、上厕所、睡觉`,指的就是`费时`的`io`操作。
单核cpu场景下,在运行的线程(进程)需要不停的切换,即“同一时刻”只有一个线程(进程)
在运行。这种场景下的多线程(进程), 称之为“并发”。
另外:现在的cpu都具有超线程能力,即1核cpu相当于2核cpu。
  • 工人有两个, 但是工具有两个。

这种情况下,老板很开心,一个萝卜一个坑,两个工人可以同时干活,可以按照自己的心愿工作。甚至指挥者都可以辞退了。

每个线程(进程)“绑定”一个cpu核心(这里涉及到cpu亲和性,不再本文的范围内),
同一时刻可以有多个线程(进程)同时运行,这种场景下多线程(进程), 称之为“并行”。
正常情况下,操作系统中的线程(进程)数量是大于核心数的。
所以调度器(指挥者)是铁定不能辞退的~~

上文是基本的概念,主要有以下几点:

  1. “同一时刻”只有一个线程(进程)在运行称之为并发,“同一时刻”有多个线程(进程)在运行称之为并行
  2. cpu需要不停的在线程(进程)间切换
  3. 进程中至少包含一个线程
进程、线程的使用场景

上文我们模糊了进程和线程的区别,现在我们来区分它们。
工人们同属于一个施工队,由一个包工头带领,做着同一个种树的项目

这里我们把`工人`理解为线程,`项目`是我们`程序`的功能,`施工队`是工作`进程`。
这里的场景我们认为这是一个“单进程”,“多线程”的程序,即一个进程中有多个线程。

工人们都在一个施工队中干活,低头不见抬头见,所以关系十分要好,常常互相分享吃的喝的。和隔壁施工队却十分疏远

同一个进程中的线程,会共享代码段,数据段,堆,
每个线程在进程的栈空间创建一个属于自己的栈空间。

有一天施工队突然工作产能跟不上了,老板只好又新找了一个施工队,两个施工队准备实施两班倒,但是因为两队之间关系疏远,每次交接工作都十分麻烦。

两个`施工队`即为两个进程,cpu在进程间切换十分费时,
并且进程间的数据在默认情况下不能共享,只能通过其他外部工具或方法进行数据交换。

所以总结一下进程和线程的区别:

  1. 线程之间切换成本小,并且数据共享,方便数据修改。并且线程的创建和销毁速度较快。但是线程间会有资源竞争,需要加锁,一个线程崩坏有可能影响同一个进程下的其他线程。
  2. 进程之间切换成本大,因为资源隔离所以不存在资源竞争,进程间也不会相互影响。但数据共享比较麻烦。

需要操作同一个对象(如变量), 需要根据某些条件频繁创建销毁,优先使用线程,反之使用进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值