go并发之goroutine和channel,并发控制入门篇

并发的概念及其重要性

这段是简单科普,大佬可以跳过

并发:并发程序指同时进行多个任务的程序。在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。

----------本段引用内容源自《GO语言高级编程》

在早期,CPU都是以单核的形式顺序执行机器指令。Go语言的祖先C语言正是这种顺序编程语言的代表。顺序编程语言中的顺序是指:所有的指令都是以串行的方式执行,在相同的时刻有且仅有一个CPU在顺序执行程序的指令。

随着处理器技术的发展,单核时代以提升处理器频率来提高运行效率的方式遇到了瓶颈,目前各种主流的CPU频率基本被锁定在了3GHZ附近。单核CPU的发展的停滞,给多核CPU的发展带来了机遇。相应地,编程语言也开始逐步向并行化的方向发展。Go语言正是在多核和网络化的时代背景下诞生的原生支持并发的编程语言。

在聊并发之前,聊聊共享变量、线程、协程

  1. 如何在不同线程/协程 共享 变量/内存?

这里留给各位看官去自行查资料,即使我列出来也不如自己动手去查记忆深刻!

不想查也可以等我下一篇文章,更加详细解读线程、进程。

  1. 线程和协程概念?

线程:线程是操作系统能够进行运算调度的最小单位。一个进程可以包含多个线程,是进程中的实际运作单位。

协程:又称微线程。协程是一种用户态的轻量级线程。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。

  1. 为什么会诞生协程?

虽然多线程在前互联网世代已经足够使用,但是线程的局限性也比较明显

  1. 线程数量有限,一般不会很多
  2. 线程占据的资源通常比我们需要的多得多,造成浪费

每个系统级线程开辟都会占用空间,这个空间可能是MB级别,但是我们如果使用的线程只需要传递KB级别数据,那么线程看起来就会比较浪费,但是又不可避免。而且线程之间的切换也会占用一些额外开销。

为了解决上面的矛盾问题,协程诞生了:更小的资源开支,动态调配资源,比线程更轻量。

协程的一些优点:

  1. 因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
  2. 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

在golang中,goroutine的创建消耗非常小,大约是KB级别。因此可以创建更多的协程,尤其是数量越多相对线程优势更加明显,而且goroutine可以动态伸缩,栈溢出风险也比线程更低。

golang的并发,goroutine的使用

var name = "yiyiyinhe"

func changeName() {
    name = "change"
}

func sayHi() {
    fmt.println("hi, ", name)
    go changeName() // 协程
}

简单的协程就创建了,那么打印出来的结果可能是hi, yiyiyinhe也可能是hi, change

如果想对某一代码块执行协程而不是某个方法,则使用下面方式

var name = "yiyiyinhe"

func sayHi() {
    fmt.println("hi, ", name)
    go func() { // 匿名函数执行协程
        name = "change"
    }
}

channel

golang对共享变量的口号

Do not communicate by sharing memory; instead, share memory by communicating.

不要通过共享内存来通信,而应通过通信来共享内存。

那么在协程中也需要进行通信,而golang使用的goroutine之间通信和同步的主要方法是channel。

什么是channel呢?

A channel is a communic ation mechanism that lets one goroutine send values to another goroutine. Each channel is a conduit for values of a particular type, called the channel’s element type.

channel是一种通信机制,它让一个goroutine向另一个goroutine发送值。每个通道都是特定类型(通道元素类型)值的管道。

简单来理解就是,channel是用于在goroutine中进行通信的管道,而且管道是有特定类型的。

创建的channel分为有缓存和无缓存两种,区别就是创建的时候是否分配大小

  • 无缓存channel

    • var ch1 = make(chan int),未分配大小
    • var ch2 = make(chan int, 0),分配大小为0也等同给于未分配大小
  • 有缓存channel

    • var :ch3 = make(int, 3),分配大小为3的有缓存channel

无缓存channel中,channel的发送操作总是在接收之前发生;简单理解就是,无缓存channel是一个管道必须从头flag<-true发送到尾部<-flag,而且尾部发生的时间一定是在头部发送之后。

  • 为什么chennel可以这样呢?

    因为channel有阻塞作用,必须接收了才能继续下去。

channel

有缓存channel则不具备上述的特性,因为对于带缓冲的Channel,对于Channel的第 K 个接收完成操作发生在第 K+C 个发送操作完成之前,其中 C 是Channel的缓存大小。 如果将 C 设置为0自然就对应无缓存的Channel,也即使第K个接收完成在第K个发送完成之前。因为无缓存的Channel只能同步发1个,也就简化为前面无缓存Channel的规则:对于从无缓冲Channel进行的接收,发生在对该Channel进行的发送完成之前。

还是上面的例子,使用channel来演示一下

var name = "yiyi"
var flag = make(chan bool) // 创建了bool类型的channel

func changeName() {
    name = "change"
    flag <- true  // 发送
}

func sayHi() {
    go changeName() // 协程
    <-flag // 接收
    fmt.println("hi, ", name)
}

那么这个时候打印出来的就是一个固定的顺序,由于<-flag接收总是在发送之后执行,因此当flag <- true执行完之前name = "change"已经执行,打印结果一定是:hi, change

上面代码等同于下图所示

image

看完你可以收获什么?

  1. 简单了解并发,了解多线程简单的发展来历
  2. 简单了解线程,协程
  3. 为什么协程会诞生?
  4. goroutine的两种使用方式
  5. channel是什么?channel的两种分类;
  6. channel在goroutine中有什么作用?

写在最后

由于我刚开始写技术文章,很多东西不知道怎么写才能让大家都看懂,就像写线程协程的时候不知道要不要解释共享变量或者共享内存是什么,也不知道大家能不能知道多线程模式下线程之间通信有哪些方式,感觉都想写但是又觉得大家看文章标题应该是了解一些东西的,如果都写篇幅太长,不写又看不懂;就觉得比较矛盾吧,也希望大家能够给我提一些意见建议!

作者还在慢慢努力,尽量把文章写的通俗易懂,排版准确,抓住重点,把最好的内容展现给大家。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容