使用channel或sync.Cond等待条件

时间:2017-01-19 21:02:03

标签: go channel condition-variable

我正在尝试等待一个特定的条件,我想建议如何做到最好。我有一个看起来像这样的结构(简化):

type view struct {
    timeFrameReached bool
    Rows []*sitRow
}

在goroutine中,我正在更新一个文件,该文件被读入view变量。行数增加,timeFrameReached最终将为true

在其他地方,我想等待以下条件成立:

view.timeFrameReached == true || len(view.Rows) >= numRows

我正在尝试学习频道以及Go的条件变量是如何工作的,我想知道这里最好的解决方案是什么。从理论上讲,我可以做一些像这样的微不足道的事情:

for {
    view = getView()
    if view.timeFrameReached == true || len(view.Rows) >= numRows {
        break
    }
}

但这显然是一个天真的解决方案。 numRows的值来自HTTP请求,因此条件方法似乎具有挑战性。 goroutine不知道何时广播条件,因为它不知道它正在寻找的行数。

2 个答案:

答案 0 :(得分:4)

我想我会用条件变量来做这件事。这个概念不仅仅是当服务员想要检查的条件为真时才进行Signal,而是当它可能是真的时(即被检查的东西已经改变)。

这样做的正常模式是:

mutex.Lock()
for {
    view = getView()
    if view.timeFrameReached == true || len(view.Rows) >= numRows {
        break
    }
    cond.Wait(&mutex)
}
// Do stuff with view
mutex.Unlock()

然后,在更改view的代码中:

mutex.Lock()
// Change view
cond.Signal() // or cond.Broadcast()
mutex.Unlock()

显然,我在不知道你的程序是如何工作的情况下编写了这个,所以你可能需要做一些改变。

你可以通过发送频道发信号并试图从频道接收等待来做与频道类似的事情,但这对我来说似乎更复杂。 (此外,如果您有多个goroutine等待,您可以通过cond.Broadcast发出警告以唤醒所有人。)

答案 1 :(得分:1)

我的一个想法是通过一个通道传递所需数量的行,构建视图的goroutine将执行非阻塞接收,以查看主线程是否正在请求一定数量的行。如果是这样,它将发回一条消息,表明条件已满足。

此处main函数请求多行:

if numRows > len(viewFile.View.Rows) && !viewFile.View.TimeFrameReached {
    // Send the required number of rows
    rows <- numRows
    // Wait for the prefetch loop to signal that the view file is ready
    <-rows // Discard the response value and move on
    view = getView()
}

这里goroutine检查是否需要一定数量的行。如果是这样,它在准备好时会以肯定的信号作出响应。该信号的价值无关紧要。

select {
    case numRows := <-rows:
        if len(viewFile.View.Rows) >= numRows || viewFile.View.TimeFrameReached {
            rows <- 1
        }
    default:
}