簡體   English   中英

與Google Go中的頻道共享資源

[英]Shared resources with channels in google go

在構建實時系統時,我正在研究Google Go語言,並且發現通過渠道進行資源共享有點令人困惑。 為了理解起見,我正在嘗試讓不同的goroutines在相同的次數上遞增和遞減一個共享值,最終以0結尾。它的。 有人在乎解釋這里出了什么問題嗎?

package main

import (
    . "fmt"
    . "runtime"
)

func increment(c chan int) {
    for x := 0; x < 10; x++ {
        a := <-c
        a++
        c <- a
    }
}

func decrement(c chan int) {
    for x := 0; x < 10; x++ {
        a := <-c
        a--
        c <- a
    }
}

func main() {
    GOMAXPROCS(NumCPU())
    c := make(chan int)
    go increment(c)
    go decrement(c)
    Println(<-c)
}

盡管我想利用Go中的通道,但我可以使用類似於CPython的互斥或信號量。

**更新

添加WaitGroup改變程序流程嗎? 我添加了一個WaitGroup ,並且效果很好。 雖然,我在整個for循環之后添加了Done()函數,然后整個increment將在decrement之前運行嗎? 我有點希望它們盡可能“並行”運行,我知道只有一個例程可以訪問我,但是我希望它們彼此獨立運行。

您的代碼存在一些問題:

  1. 兩個goroutine都嘗試同時從通道讀取。 這是一個僵局,因為通道中沒有要讀取的內容。

  2. Println(<-c)從通道讀取一個值,而不是結果。 如果您等待兩個goroutine完成,則可能會讀取結果,但這需要添加WaitGroup Waitgroup就像一個信號量,它允許每個goroutine減少待處理goroutine的計數器,並允許調用方等待它們完成某些任務。

  3. 因為如果沒有閱讀器則發送阻塞,而如果沒有發送者,則讀取阻塞,而您就是。 等待兩個goroutine都先完成,然后b。 要進行比寫入更多的讀取(Println讀取),您需要一個buffered channel ,該buffered channel在緩沖區中恰好有一個額外的位置。

  4. 您需要在通道中推送一個初始值以啟動過程。

我已經對您的代碼進行了一些更改,並且此示例現在可以正常工作(盡管請注意,它並不是真正的增量->減量->增量-> ....,但更復雜的是增量->增量-> ...->減量->減量-> ....直到完成。

package main

import (
    . "fmt"
    . "runtime"
    "sync"
)

func increment(c chan int, wg *sync.WaitGroup) {
    for x := 0; x < 10; x++ {
        a := <-c
        Println("increment read ", a)
        a++
        c <- a
    }
    Println("Incrment done!")
    wg.Done()
}

func decrement(c chan int, wg *sync.WaitGroup) {
    for x := 0; x < 10; x++ {
        a := <-c
        Println("Decrement read ", a)       
        a--
        c <- a
    }
    Println("Dencrment done!")  
    wg.Done()
}

func main() {
    GOMAXPROCS(NumCPU())

    //we create a buffered channel with 1 extra space. This means 
    //you can send one extra value into it if there is no reader, allowing for the final result to be pushed to println
    c := make(chan int, 1)

    //we create a wait group so we can wait for both goroutines to finish before reading the result
    wg := sync.WaitGroup{}
    wg.Add(1) //mark one started
    go increment(c, &wg)
    wg.Add(1) //mark another one started. We can just do Add(2) BTW
    go decrement(c, &wg)

    //now we push the initial value to the channel, starting the dialog
    c <- 0

    //let's wait for them to finish...
    wg.Wait()

    //now we have the result in the channel's buffer
    Println("Total: ", <-c )
}

這是我認為您在談論的那種共享狀態引擎的完整示例

請注意,如您在編輯中建議的那樣使用WaitGroup來同步兩個通道。

PS不使用import . "fmt" import . "fmt"被認為是不好的做法。

package main

import (
    "fmt"
    "runtime"
    "sync"
)

// Commands for the engine
const (
    INC = iota
    DEC
    ANSWER
    QUIT
)

// Engine which takes commands and acts on some shared state
func engine(c chan int, reply chan int) {
    counter := 0
    for {
        switch <-c {
        case INC:
            counter++
        case DEC:
            counter--
        case ANSWER:
            reply <- counter
        case QUIT:
            reply <- counter
            return

        }
    }
}

// Add n times then signal done via the waitgroup
func increment(n int, c chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for x := 0; x < n; x++ {
        c <- INC
    }
}

// Subtract n times then signal done
func decrement(n int, c chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for x := 0; x < n; x++ {
        c <- DEC
    }
}

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())

    // Start the engine
    c := make(chan int)
    reply := make(chan int)
    go engine(c, reply)

    // Do adding and subtracting and wait for them to finish
    wg := new(sync.WaitGroup)
    wg.Add(2)
    go increment(101, c, wg)
    go decrement(100, c, wg)
    wg.Wait()

    // Read the answer
    c <- ANSWER
    fmt.Printf("Total is %d\n", <-reply)

    // Stop the engine
    c <- QUIT
    <-reply
    fmt.Printf("All done\n")
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM