我通过运气解决的Golang僵局,需要解释

时间:2017-08-14 21:32:44

标签: go

我正在努力了解去频道和常规。为此,我正在进行在线练习。我在这里找到了一个:http://whipperstacker.com/2015/10/05/3-trivial-concurrency-exercises-for-the-confused-newbie-gopher/

我解决了第3个问题(名为“网吧”)。 但是有一些我通过“运气”解决的问题,这让我感到烦恼,因为我不理解我的问题以及为什么我的“黑客”修复了它。

在我的下面的代码中,我将“enterChan< - next”替换为“go func(){enterChan< - next}()”,它解决了我的僵局。

有人可以向我解释为什么它之前会陷入僵局,为什么它会与这个黑客一起工作?这是一个合适的解决方案,还是一个丑陋的解决方案?

不要犹豫批评我的代码,我正在寻求改进:)

非常感谢!

这是我的代码:

package main

import (
    "fmt"
    "math/rand"
    "strconv"
    "time"
)

const (
    maxNumberOfUser = 8
)

func useComputer(tourist string, leaverChan chan string) {
    seed := rand.NewSource(time.Now().UnixNano())
    random := rand.New(seed)
    fmt.Println(tourist, "is online")
    d := random.Intn(120-15) + 15
    time.Sleep(time.Duration(d) * time.Millisecond * 10)
    fmt.Println(tourist, "is done, having spent", d, "minutes online.")
    leaverChan <- tourist
}

func manageUsers(enterChan, leaverChan chan string, stopChan chan struct{}) {
    nbUsed := 0
    queue := make([]string, 0)
    for {
        select {
        case tourist := <-enterChan:
            if nbUsed < maxNumberOfUser {
                nbUsed++
                go useComputer(tourist, leaverChan)
            } else {
                fmt.Println(tourist, "waiting for turn.")
                queue = append(queue, tourist)
            }
        case tourist := <-leaverChan:
            nbUsed--
            fmt.Println(tourist, "is leaving, number of free place is now:", maxNumberOfUser-nbUsed)
            if len(queue) > 0 {
                next := queue[0]
                queue = queue[1:]
                go func() {
                    enterChan <- next
                }()
            } else if nbUsed == 0 {
                close(stopChan)
                return
            }

        }
    }
}

func main() {
    enterChan := make(chan string)
    leaverChan := make(chan string)
    stopChan := make(chan struct{})
    go manageUsers(enterChan, leaverChan, stopChan)

    for i := 1; i <= 25; i++ {
        enterChan <- "Tourist " + strconv.Itoa(i)
    }
    <-stopChan
    fmt.Println("The place is empty, let's close up and go to the beach!")
}

1 个答案:

答案 0 :(得分:0)

如@ dev.bmax所述, enterChan 不是缓冲通道,您正尝试将数据发送到未被读取的通道。例如,下面的代码会导致死锁错误:

package main
import (
    "fmt"
)


func main() {
    stream := make(chan int)
    <-stream
    stream<-1

    fmt.Println("Yayyy!! no deadlock!")
}

您可以运行上面的代码here并检查它是否具有死锁。但是,如果我将其更改为:

package main
import (
    "fmt"
)


func main() {
    stream := make(chan int)
    go func(){<-stream}()
    stream<-1
    fmt.Println("Yayyy!! no deadlock!")
}

我们没有僵局。因为我们启动了另一个从通道读取的GoRoutine,而主GoRoutine正在将数据推送到通道。希望这会有所帮助!