[英]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
中的通道,但我可以使用類似於C
或Python
的互斥或信號量。
**更新
添加WaitGroup
改變程序流程嗎? 我添加了一個WaitGroup
,並且效果很好。 雖然,我在整個for循環之后添加了Done()
函數,然后整個increment
將在decrement
之前運行嗎? 我有點希望它們盡可能“並行”運行,我知道只有一個例程可以訪問我,但是我希望它們彼此獨立運行。
您的代碼存在一些問題:
兩個goroutine都嘗試同時從通道讀取。 這是一個僵局,因為通道中沒有要讀取的內容。
Println(<-c)
從通道讀取一個值,而不是結果。 如果您等待兩個goroutine完成,則可能會讀取結果,但這需要添加WaitGroup
。 Waitgroup就像一個信號量,它允許每個goroutine減少待處理goroutine的計數器,並允許調用方等待它們完成某些任務。
因為如果沒有閱讀器則發送阻塞,而如果沒有發送者,則讀取阻塞,而您就是。 等待兩個goroutine都先完成,然后b。 要進行比寫入更多的讀取(Println讀取),您需要一個buffered channel
,該buffered channel
在緩沖區中恰好有一個額外的位置。
您需要在通道中推送一個初始值以啟動過程。
我已經對您的代碼進行了一些更改,並且此示例現在可以正常工作(盡管請注意,它並不是真正的增量->減量->增量-> ....,但更復雜的是增量->增量-> ...->減量->減量-> ....直到完成。
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.