日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

goroutine, channel 和 CSP

發(fā)布時間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 goroutine, channel 和 CSP 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

引子

老聽 clojure 社區(qū)的人提起?core.async?,說它如何好用,如何簡化了并發(fā)編程的模型,不由得勾起了我的好奇心,想了解一番其思想的源頭:CSP 模型及受其啟發(fā)的 goroutine 和 channel 。

CSP 模型

CSP 描述這樣一種并發(fā)模型:多個Process 使用一個 Channel 進(jìn)行通信, ?這個 Channel 連結(jié)的 Process 通常是匿名的,消息傳遞通常是同步的(有別于 Actor Model)。

CSP 最早是由?Tony Hoare?在 1977 年提出,據(jù)說老爺子至今仍在更新這個理論模型,有興趣的朋友可以自行查閱電子版本:http://www.usingcsp.com/cspbook.pdf。

嚴(yán)格來說,CSP 是一門形式語言(類似于 ? calculus),用于描述并發(fā)系統(tǒng)中的互動模式,也因此成為一眾面向并發(fā)的編程語言的理論源頭,并衍生出了 Occam/Limbo/Golang…

而具體到編程語言,如 Golang,其實只用到了 CSP 的很小一部分,即理論中的 Process/Channel(對應(yīng)到語言中的 goroutine/channel):這兩個并發(fā)原語之間沒有從屬關(guān)系, Process 可以訂閱任意個 Channel,Channel 也并不關(guān)心是哪個 Process 在利用它進(jìn)行通信;Process 圍繞 Channel 進(jìn)行讀寫,形成一套有序阻塞和可預(yù)測的并發(fā)模型。

goroutine

What is a goroutine? It’s an independently executing function, launched by a?go?statement.
It has its own call stack, which grows and shrinks as required.
It’s very cheap. It’s practical to have thousands, even hundreds of thousands of goroutines.
It’s not a thread.
There might be only one thread in a program with thousands of goroutines.
Instead, goroutines are multiplexed dynamically onto threads as needed to keep all the goroutines running.
But if you think of it as a very cheap thread, you won’t be far off.

―?Rob Pike

以上是 Rob Pike 在?Google I/O 2012?上給出的描述,概括下來其實就一句話:

goroutine 可以視為開銷很小的線程(既不是物理線程也不是協(xié)程,但它擁有自己的調(diào)用棧,并且這個棧的大小是可伸縮的 ?不是協(xié)程,它有自己的棧),很好用,需要并發(fā)的地方就用 go 起一個 func,goroutine走起?

在 Golang 中,任何代碼都是運(yùn)行在 goroutine里,即便沒有顯式的?go func(),默認(rèn)的 main 函數(shù)也是一個 goroutine。

但 goroutine 不等于操作系統(tǒng)的線程,它與系統(tǒng)線程的對應(yīng)關(guān)系,牽涉到 Golang 運(yùn)行時的調(diào)度器:

Golang?Scheduler

調(diào)度器由三方面實體構(gòu)成:

  • M:物理線程,類似于 POSIX 的標(biāo)準(zhǔn)線程;
  • G:goroutine,它擁有自己的棧、指令指針和維護(hù)其他調(diào)度相關(guān)的信息;
  • P:代表調(diào)度上下文,可將其視為一個局部調(diào)度器,使Golang代碼跑在一個線程上
  • 三者對應(yīng)關(guān)系:

    上圖有2個 物理線程 M,每一個 M 都擁有一個上下文(P),每一個也都有一個正在運(yùn)行的goroutine(G)。

    P 的數(shù)量可由?runtime.GOMAXPROCS()?進(jìn)行設(shè)置,它代表了真正的并發(fā)能力,即可有多少個 goroutine?同時運(yùn)行。

    調(diào)度器為什么要維護(hù)多個上下文P 呢?因為當(dāng)一個物理線程 M 被阻塞時,P 可以轉(zhuǎn)而投奔另一個OS線程 M(即 P 帶著 G 連莖拔起,去另一個 M 節(jié)點下運(yùn)行)。這是 Golang調(diào)度器厲害的地方,也是高并發(fā)能力的保障。

    channel

    channel 是 goroutine 之間通信(讀寫)的通道。因為它的存在,顯得 Golang(或者說CSP)與傳統(tǒng)的共享內(nèi)存型的并發(fā)模型截然不同,用?Effective Go?里的話來說就是:

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

    在 Golang 的并發(fā)模型中,我們并不關(guān)心是哪個 goroutine(匿名性)在用 channel,只關(guān)心 channel 的性質(zhì):

    • 是只讀還是只寫?
    • 傳遞的數(shù)據(jù)類型?
    • 是否有緩沖區(qū)?

    比如我希望在程序里并發(fā)的計算并傳遞一個整型值,我就會定義一個 int 型的 channel:

    value := make(chan int)

    無緩沖的 channel由于 make 這個 channel 并未提供第二個參數(shù)capacity,因此這個 channel 是不帶緩沖區(qū)的,即同步阻塞的channel:

    它有如下特點:

    1. 不可以在同一個 goroutine 中既讀又寫,否則將會死鎖,拋出如

    fatal error: all goroutines are asleep - deadlock!

    這樣的錯誤,以下代碼片斷是這種典型:

    func deadlock() {ch := make(chan int)ch <- 2x := <-chlog.Println(x)}


    2. ?兩個goroutine中使用無緩沖的channel,則讀寫互為阻塞,即雙方代碼的執(zhí)行都會阻塞在 <-ch 和 ch <- 處,只到雙方讀寫完成在 ch 中的傳遞,各自繼續(xù)向下執(zhí)行,此處借用CSP 圖例說明:

    goroutine 在無緩沖 channel 上交互的代碼:

    func nolock() {ch := make(chan int)go func() {ch <- 2log.Println("after write")}()x := <-chlog.Println("after read:", x)}

    有緩沖的 channel

    在 make 時傳遞第二參 capacity,即為有緩沖的 channel:

    ch := make(chan int, 1)

    這樣的 channel 無論是否在同一 goroutine 中,均可讀寫而不致死鎖,看看如下片斷,你猜它會輸出什么:

    ch := make(chan int, 1)for i := 0; i < 10; i++ {select {case x := <-ch:fmt.Println(x)case ch <- i:}}

    舉個粟子

    網(wǎng)上看來的求素數(shù)的例子:使用若干個 goroutine (根據(jù)求解范圍 N 而定)做素數(shù)的篩法,即

    從2開始每找到一個素數(shù)就標(biāo)記所有能被該素數(shù)整除的所有數(shù)。直到?jīng)]有可標(biāo)記的數(shù),剩下的就都是素數(shù)。下面以找出10以內(nèi)所有素數(shù)為例,借用 CSP 方式解決這個問題。

    代碼如下:

    package mainimport "fmt"func Processor(seq <-chan int, wait chan struct{}, level int) {go func() {prime, ok := <-seqif !ok {close(wait)return}fmt.Printf("[%d]: %d\n", level, prime)out := make(chan int)Processor(out, wait, level+1)for num := range seq {if num%prime != 0 {out <- num}}close(out)}()}func main() {origin, wait := make(chan int), make(chan struct{})Processor(origin, wait, 1)for num := 2; num < 10; num++ {origin <- num}close(origin)<-wait}

    FAQ

    • Q:goroutine 什么情況下會產(chǎn)生 leak?
    • A:channel 上只有 send 沒有 receive
    • Q:讀一個已經(jīng)關(guān)閉的 channel ?只會讀取到 0 值,有什么辦法應(yīng)對?
    • A:要么在 receive 時加上第二個參數(shù),如?v, ok :=,要么使用?v := range ch?形式接收
    • Q:寫一個已經(jīng)關(guān)閉的 channel 會有什么結(jié)果?
    • A:會 panic
    • Q:學(xué)習(xí) Golang 有什么好的材料
    • A:官網(wǎng),及下邊這本 Golang圣經(jīng)

    ?

    引用

  • https://en.wikipedia.org/wiki/Communicating_sequential_processes
  • https://36kr.com/p/5073181.html
  • http://arild.github.io/csp-presentation
  • http://zora.ghost.io/jian-yi-callback-actor-csp/
  • http://www.jdon.com/concurrent/actor-csp.html
  • http://www.jtolds.com/writing/2016/03/go-channels-are-bad-and-you-should-feel-bad/
  • https://blog.golang.org/share-memory-by-communicating
  • https://talks.golang.org/2012/concurrency.slide
  • https://www.zhihu.com/question/20862617/answer/27964865
  • https://blog.golang.org/pipelines
  • 轉(zhuǎn)載于:https://my.oschina.net/u/2245781/blog/1615181

    總結(jié)

    以上是生活随笔為你收集整理的goroutine, channel 和 CSP的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。