自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

以可視化方式解釋 Go 并發(fā) - 通道

開發(fā)
在本文中,我將使用 Gopher 運(yùn)行他們的虛構(gòu)咖啡館的可愛比喻來闡述通道,因?yàn)槲覉?jiān)信人類更容易通過視覺學(xué)習(xí)。

在并發(fā)編程中,許多編程語言采用共享內(nèi)存/狀態(tài)模型。然而,Go 通過實(shí)現(xiàn) 通信順序進(jìn)程 (CSP) 區(qū)別于眾多語言。在 CSP 中,一個(gè)程序由并行的進(jìn)程組成,這些進(jìn)程不共享狀態(tài),而是使用通道進(jìn)行通信和同步它們的操作。因此,對(duì)于有意采用 Go 的開發(fā)人員來說,理解通道的工作原理變得至關(guān)重要。在本文中,我將使用 Gopher 運(yùn)行他們的虛構(gòu)咖啡館的可愛比喻來闡述通道,因?yàn)槲覉?jiān)信人類更容易通過視覺學(xué)習(xí)。

情景

Partier、Candier 和 Stringer 經(jīng)營一家咖啡館。由于制作咖啡需要比接受訂單更多的時(shí)間,Partier 將協(xié)助接受客戶的訂單,然后將這些訂單傳遞到廚房,Candier 和 Stringer 在那里制作咖啡。

Gopher's Cafe

無緩沖通道

最初,咖啡館以最簡單的方式運(yùn)營:每當(dāng)收到新訂單時(shí),Partier 將訂單放入通道中,并等待 Candier 或 Stringer 中的任何一個(gè)在接受新訂單之前取走它。這種 Partier 和廚房之間的通信是通過無緩沖通道實(shí)現(xiàn)的,使用 ch := make(chan Order) 創(chuàng)建。當(dāng)通道中沒有待處理的訂單時(shí),即使 Stringer 和 Candier 都準(zhǔn)備好接受新訂單,它們也會(huì)保持空閑狀態(tài),等待新訂單到來。

無緩沖通道

當(dāng)收到新訂單時(shí),Partier 將其放入通道中,使訂單可以被 Candier 或 Stringer 之一接受。但是,在繼續(xù)接受新訂單之前,Partier 必須等待其中一個(gè)從通道中獲取訂單。

由于 Stringer 和 Candier 都可以接受新訂單,因此訂單將立即被其中一個(gè)接受。但是,不能保證或預(yù)測哪個(gè)具體的接收者會(huì)獲取訂單。在 Stringer 和 Candier 之間的選擇是非確定性的,它依賴于諸如調(diào)度和 Go 運(yùn)行時(shí)的內(nèi)部機(jī)制等因素。假設(shè) Candier 獲取了第一個(gè)訂單。

Candier 完成處理第一個(gè)訂單后,她回到等待狀態(tài)。如果沒有新訂單到達(dá),那么 Candier 和 Stringer 這兩名工作人員都會(huì)保持空閑狀態(tài),直到 Partier 將另一個(gè)訂單放入通道中供他們處理。

當(dāng)新訂單到達(dá)并且 Stringer 和 Candier 都可以處理它時(shí),即使 Candier 剛剛處理了前一個(gè)訂單,接收新訂單的具體工作人員仍然是不確定的。在這種情況下,假設(shè) Candier 再次被分配為第二個(gè)訂單的接收者。

在新訂單 order3 到達(dá)時(shí),Candier 正在處理 order2,她沒有等待在行 order := <-ch 處,因此 Stringer 成為唯一可以接收 order3 的工作人員。因此,他會(huì)接收到它。

在將 order3 發(fā)送給 Stringer 后不久,order4 到達(dá)。此時(shí),Stringer 和 Candier 已經(jīng)忙于處理各自的訂單,沒有人可以接收 order4。由于通道沒有緩沖,將 order4 放入通道會(huì)阻塞 Partier,直到 Stringer 或 Candier 可以接收 order4 為止。這種情況值得特別注意,因?yàn)槲医?jīng)??吹饺藗儗?duì)無緩沖通道(使用 make(chan order) 或 make(chan order, 0) 創(chuàng)建)和具有緩沖大小為 1 的通道(使用 make(chan order, 1) 創(chuàng)建)感到困惑。因此,他們錯(cuò)誤地期望 ch <- order4 立即完成,允許 Partier 在 ch <- order5 處被阻塞之前接受 order5。如果您也是這樣認(rèn)為的,我已經(jīng)在 Go Playground 上創(chuàng)建了一個(gè)代碼片段,以幫助您糾正您的誤解 https://go.dev/play/p/shRNiDDJYB4。

帶緩沖通道

無緩沖通道是有效的,但它限制了總吞吐量。如果他們只接受一些訂單以便在后端(廚房)順序處理它們,那將更好。這可以通過使用帶緩沖通道來實(shí)現(xiàn)。現(xiàn)在,即使 Stringer 和 Candier 忙于處理他們的訂單,只要通道不滿,例如最多 3 個(gè)待處理訂單,Partier 仍然可以將新訂單放入通道并繼續(xù)接受其他訂單。

1*TCrrdUaa7XPcmRSDIO7xEQ.png

引入帶緩沖通道后,咖啡館增強(qiáng)了處理更多訂單的能力。然而,選擇適當(dāng)?shù)木彌_區(qū)大小以保持客戶合理的等待時(shí)間非常重要。畢竟,沒有客戶想忍受過長的等待時(shí)間。有時(shí),拒絕新訂單可能比接受新訂單但無法及時(shí)完成它們更可接受。此外,在使用帶緩沖通道的瞬時(shí)容器化(Docker)應(yīng)用程序時(shí)要小心,因?yàn)轭A(yù)計(jì)會(huì)隨機(jī)重啟,在這種情況下,從通道中恢復(fù)消息可能是一項(xiàng)具有挑戰(zhàn)性甚至不可能的任務(wù)。

通道 vs 阻塞隊(duì)列

盡管基本上不同,Java 中的阻塞隊(duì)列用于線程之間的通信,而 Go 中的通道用于 Goroutine 的通信,但阻塞隊(duì)列和通道在某種程度上表現(xiàn)出相似之處。如果您熟悉阻塞隊(duì)列,那么理解通道肯定會(huì)更容易。

常見用途

通道是 Go 應(yīng)用程序中的基本和廣泛使用的功能,可以用于各種用途。通道的一些常見用例包括:

  • Goroutine 通信:通道允許不同 Goroutine 之間進(jìn)行消息交換,使它們能夠協(xié)作而無需直接共享狀態(tài)。
  • 工作池:如上面的示例所示,通道經(jīng)常用于管理工作池,其中多個(gè)相同的工作程序從共享通道中處理傳入任務(wù)。
  • 分發(fā)和匯總:通道促進(jìn)了分發(fā)和匯總模式,多個(gè) Goroutine(分發(fā))執(zhí)行工作并將結(jié)果發(fā)送到單個(gè)通道,而另一個(gè) Goroutine(匯總)消耗這些結(jié)果。
  • 超時(shí)和截止期:通道與 select 語句結(jié)合使用,可以用于處理超時(shí)和截止期,確保程序可以優(yōu)雅地處理延遲并避免無限等待。

我將在其他文章中更詳細(xì)地探討通道的不同用法。但是,目前,讓我們通過實(shí)現(xiàn)上述咖啡館場景來結(jié)束這篇介紹性博客,并觀察通道如何在其中發(fā)揮作用。我們將探討 Partier、Candier 和 Stringer 之間的互動(dòng),并觀察通道如何促進(jìn)它們之間的順暢通信和協(xié)調(diào),從而實(shí)現(xiàn)咖啡館中的高效訂單處理和同步。

演示代碼

package main

import (
    "fmt"
    "log"
    "math/rand"
    "sync"
    "time"
)

func main() {
    ch := make(chan order, 3)
    wg := &sync.WaitGroup{}
    wg.Add(2)

    go func() {
        defer wg.Done()
        worker("Candier", ch)
    }()

    go func() {
        defer wg.Done()
        worker("Stringer", ch)
    }()

    for i := 0; i < 10; i++ {
        waitForOrders()
        o := order(i)
        log.Printf("Partier: I %v, I will pass it to the channel\n", o)
        ch <- o
    }

    log.Println("No more orders, closing the channel to signify workers to stop")
    close(ch)

    log.Println("Wait for workers to gracefully stop")
    wg.Wait()

    log.Println("All done")
}

func waitForOrders() {
    processingTime := time.Duration(rand.Intn(2)) * time.Second
    time.Sleep(processingTime)
}

func worker(name string, ch <-chan order) {
    for o := range ch {
        log.Printf("%s: I got %v, I will process it\n", name, o)
        processOrder(o)
        log.Printf("%s: I completed %v, I'm ready to take a new order\n", name, o)
    }

    log.Printf("%s: I'm done\n", name)
}

func processOrder(_ order) {
    processingTime := time.Duration(2+rand.Intn(2)) * time.Second
    time.Sleep(processingTime)
}

type order int

func (o order) String() string {
    return fmt.Sprintf("order-%02d", o)
}

您可以復(fù)制此代碼,在您的 IDE 上進(jìn)行調(diào)整并運(yùn)行,以更好地理解通道的工作原理。

責(zé)任編輯:趙寧寧 來源: 小技術(shù)君
相關(guān)推薦

2023-10-06 23:31:25

可視化Go

2023-09-15 11:32:18

selectGo可視化解釋

2023-09-25 12:45:45

Go 語言可視化sync.Mute

2023-10-20 13:35:19

GoWaitGroup

2017-11-10 11:27:48

Go并行算法

2023-05-08 16:29:34

2020-03-11 14:39:26

數(shù)據(jù)可視化地圖可視化地理信息

2017-04-19 08:32:50

大數(shù)據(jù)數(shù)據(jù)可視化編程工具

2017-10-14 13:54:26

數(shù)據(jù)可視化數(shù)據(jù)信息可視化

2022-08-26 09:15:58

Python可視化plotly

2009-04-21 14:26:41

可視化監(jiān)控IT管理摩卡

2015-08-20 10:06:36

可視化

2024-04-11 07:40:55

Go并發(fā)編程

2024-05-06 07:53:09

Go并發(fā)編程

2018-03-27 22:40:59

深度學(xué)習(xí)

2019-03-05 09:20:47

Vim可視化模式命令

2014-01-17 10:36:39

2015-08-20 10:00:45

可視化

2020-09-27 11:15:37

可視化PandasPython

2017-07-10 14:18:34

微服務(wù)架構(gòu)可視化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)