英文:
Using channel or sync.Cond to wait for condition
问题
我正在尝试等待特定条件的发生,并且我想知道如何最好地实现。我有一个简化版的结构体如下:
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 不知道何时广播条件,因为它不知道它要寻找多少行。
英文:
I am trying to wait for a specific condition, and I would like advice as to how this is done best. I have a struct that looks like this (simplified):
type view struct {
timeFrameReached bool
Rows []*sitRow
}
In a goroutine, I am updating a file, which is read into the view
variable. The number of rows increases, and timeFrameReached
will ultimately be true
.
Elsewhere, I want to wait for the following condition to be true:
view.timeFrameReached == true || len(view.Rows) >= numRows
I am trying to learn channels and how Go's condition variables work, and I would like to know what is the best solution here. Theoretically, I could do something trivial like this:
for {
view = getView()
if view.timeFrameReached == true || len(view.Rows) >= numRows {
break
}
}
but that is obviously a naive solution. The value of numRows
comes from an HTTP request, so the condition method seems challenging. The goroutine would not know when to broadcast the condition because it wouldn't know the number of rows it is looking for.
答案1
得分: 4
我认为你可以使用条件变量来实现这个功能。这个概念并不是说只有在等待者想要检查的条件为真时才应该执行信号,而是当条件可能为真时(即被检查的事物发生了变化)。
通常的做法是:
mutex.Lock()
for {
view = getView()
if view.timeFrameReached == true || len(view.Rows) >= numRows {
break
}
cond.Wait(&mutex)
}
// 处理 view
mutex.Unlock()
然后,在修改 view
的代码中:
mutex.Lock()
// 修改 view
cond.Signal() // 或者 cond.Broadcast()
mutex.Unlock()
显然,我不知道你的程序如何工作,所以你可能需要进行一些修改。
你也可以使用通道来实现类似的功能,通过在通道上发送信号来通知,通过尝试从通道接收来等待,但我觉得这种方法更加复杂。(另外,如果有多个 goroutine 在等待,你可以使用 cond.Broadcast
来唤醒所有的 goroutine。)
英文:
I think I would do this with a condition variable. The concept is not that a Signal
should only be done when the condition the waiter wants to check is true, but when it might be true (i.e., the things being checked have changed).
The normal pattern for doing this is:
mutex.Lock()
for {
view = getView()
if view.timeFrameReached == true || len(view.Rows) >= numRows {
break
}
cond.Wait(&mutex)
}
// Do stuff with view
mutex.Unlock()
Then, in the code where view
is changed:
mutex.Lock()
// Change view
cond.Signal() // or cond.Broadcast()
mutex.Unlock()
Obviously, I've written this without knowing how your program works, so you may have to make some changes.
You could do something similar with a channel by sending on the channel to signal and trying to receive from the channel to wait, but that seems more complicated to me. (Also, if you have more than one goroutine waiting, you can signal all of them to wake up using cond.Broadcast
.)
答案2
得分: 1
我有一个想法,涉及通过通道传递所需的行数,构建视图的 goroutine 将进行非阻塞接收,以查看主线程是否请求特定数量的行。如果是这样,它将发送一条消息回来表示条件已满足。
这里的 main
函数请求一定数量的行:
if numRows > len(viewFile.View.Rows) && !viewFile.View.TimeFrameReached {
// 发送所需的行数
rows <- numRows
// 等待预取循环发出视图文件已准备好的信号
<-rows // 丢弃响应值并继续执行
view = getView()
}
这里的 goroutine 检查是否需要一定数量的行。如果是这样,它在准备好时回复一个肯定的信号。该信号的值无关紧要。
select {
case numRows := <-rows:
if len(viewFile.View.Rows) >= numRows || viewFile.View.TimeFrameReached {
rows <- 1
}
default:
}
英文:
One idea I have involves communicating the needed number of rows via a channel, and the goroutine that is building the view will do a non-blocking receive to see if the main thread is requesting a certain number of rows. If so, it will send a message back to indicate that the condition is met.
Here the main
function requests a number of rows:
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()
}
Here the goroutine checks if a certain number of rows are required. If so, it responds with an affirmative signal when ready. The value of that signal is inconsequential.
select {
case numRows := <-rows:
if len(viewFile.View.Rows) >= numRows || viewFile.View.TimeFrameReached {
rows <- 1
}
default:
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论