从三体质子锁定地球科技 简析Golang的并发

从三体质子锁定地球科技 简析Golang的并发

好吧,我承认这个标题是骗你进来的,那么来都来了,看完再走吧。

——

通常情况下,我们都会觉得golang有着不错的性能。那么这个不错的性能是如何得出的呢?我觉得大概有以下几点

  • 静态语言VS动态语言
    静态语言通常有着比解释型语言更好的性能. 静态语言需要预先编译成二进制机器语言,执行效率自然比解释型语言的解释器边解释边执行效率要高出不少.
    所以,单从执行效率上看,C/C++/C#/Java/Golang 等静态要比 Python/Javascript/Ruby等 动态语言要高出不少

  • GC(Garbage Collection)
    相比Java的虚拟机JVM或C# 的.NET Framework 提供的垃圾回收机制,Golang有着更高的效率.
    详细上,Golang的GC咱没做过仔细研究,.NET 的GC有着引用计数以及三代的垃圾处理机制,实际上,微软在.net core里也做了一定的优化,但总归来说,Golang的GC更加的轻量,执行效率也更高(没有虚拟机呀).

  • 并发VS并行
    并发:同一时刻,通过调度,来回切换交替运行多个任务,给人的感觉是同时运行的
    并行:同一时刻,多个任务同时在运行.

回到标题,在科幻小说<<三体>>中,三体星人通过发送到地球的一个高维展开过的质子就能搅乱地球的所有粒子对撞机的规律, 那么,三体的质子应该是并发来处理的而不是并行的来执行干扰工作.
并发通过切换CPU运行时间片,能达到非常高的执行效率。尤其是在IO密集的计算中.

Golang 使用goroutine 来支持并发, goroutine说白了其实就是协程,但是它比线程轻量。线程的建立需要较多的资源消耗,但是, 执行goroutine只需极少的栈内存。


Golang中的并发

虽然并发并非golang所特有, 比如python就有对协程的支持。但是就便捷性上来讲,Golang从语言层面就支持了并发,使用起来也更加方便.

goroutine通过在函数前加 go关键字实现, 一个官方的例子.

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(time.Millisecond * 10)
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}

执行结果:
hello
world
hello
world
world
hello
world
hello
world
hello

Channel

goroutine的函数运行在相同的地址空间,那么就必须做好内存同步工作。相比其它语言的多线程同步锁,golang 使用channel 来进行数据通信, 显得非常的优秀和高效。 channel 可以发送也可以接受channel 类型的值. 我们可以使用make来定义一个channel.

var ch_i = make(chan int)
var ch_s = make(chan string)
var ch_st = make(chan struct{})

举个栗子。
我们要计算一个数组所有元素的累加和, 我们可以把相应的数组拆成若干个goroutine并发执行.

package main

import "fmt"

func sum(a []int, c chan int) {
    total := 0
    for _, v := range a {
        total += v
    }
    c <- total
}

func main() {
    a := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(a[:2], c)
    go sum(a[2:4], c)
    go sum(a[4:], c)
    x, y, z := <-c, <-c, <-c

    fmt.Println(x, y, z, x+y+z)
}

执行结果:
4 -1 9 12
三个协程并发计算结果并通过channel 来传递数据.
通过 c <- total, 把计算结果传递给channel, 通过 x, y, z := <-c, <-c, <-c 来接受channel的值.

带缓存的channel

默认的channel是不带缓存的,但我们也可以创建带缓存的channel. 在channel创建的时候可以指定缓存大小。
在缓存大小范围内,就可以一直往channel里塞。直到塞满,阻塞。再直到有人从channel取出,释放缓存。

举个栗子。
我们定义一个带缓存的channel,用来存储斐波那契数组.

package main

import "fmt"

func fibonacci(n int, c chan int) {
    x, y := 1, 1
    for i := 0; i < n; i++ {
        c <- x
        x, y = y, x+y
    }
}

func main() {
    c := make(chan int, 5)
    go fibonacci(cap(c), c)
    x, y, z, a, b := <-c, <-c, <-c, <-c, <-c
    fmt.Println(x, y, z, a, b)
}

运行结果:
1 1 2 3 5

遍历/关闭 channel

上面的例子略显丑,我们可以通过range 函数来遍历缓存里的值.

package main

import "fmt"

func fibonacci(n int, c chan int) {
    x, y := 1, 1
    for i := 0; i < n; i++ {
        c <- x
        x, y = y, x+y
    }
}

func main() {
    c := make(chan int, 10)
    go fibonacci(cap(c), c)
    for i := range c {
        fmt.Println(i)
    }
}

运行结果:
1
1
2
3
5
8
13
21
34
55
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
C:/Users/trump/go/src/github.com/goroutine-test/main.go:16 +0xb9

系统报了一个错误,意思是说所有的goroutines 都没了。原因就是,range 函数在channel 没有关闭的时候会一直运行,10个读完了以后,没有新的数值进来,它就死了。

解决办法:
在fibonacci函数中关闭通道。

package main

import "fmt"

func fibonacci(n int, c chan int) {
    x, y := 1, 1
    for i := 0; i < n; i++ {
        c <- x
        x, 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)
    }
}

总结

以上就是个人对Golang 并发的一些粗浅理解。
虽然您可能被骗了,但如果文章对你有所帮助,也是值了。谢谢。

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