如何使用 sync.Cond 对在无限循环上运行的 goroutine 进行单元测试?
How can I unit test a goroutine that runs on an infinite for loop using sync.Cond?
我正在尝试对在无限循环上运行的通道进行单元测试。我想我已经找到了一种方法,但我不确定这是否是使用条件变量的有效方法。另外我不确定这种方法是否容易出现竞争条件。由于 for 循环在其自己的 goroutine 上是 运行,当我到达 "cond.Wait()?" 时,通道是否可能会耗尽?如果发生这种情况,我会永远挂起吗?在我见过的所有使用条件变量的示例中,它们通常伴随着一个围绕等待的 for 循环。我这里需要这个吗?我的问题:我在这里使用的方法有什么问题吗?这是valid/idiomatic条件变量的使用吗?
package main
import (
"fmt"
"sync"
)
var doStuffChan chan bool
var cond *sync.Cond
var result string
func main() {
doStuffChan = make(chan bool, 10)
cond = &sync.Cond{L: &sync.Mutex{}}
go startDoStuffLoop()
doStuffChan <- true
cond.L.Lock()
cond.Wait()
cond.L.Unlock()
fmt.Println(result)
}
func startDoStuffLoop() {
for {
<-doStuffChan
result = "success"
cond.Broadcast()
}
}
在我看来,您的所有假设都是正确的。为避免通道耗尽,只需使用
close(doStuffChan)
而不是 doStuffChan <- true
,因为您可以永远从关闭的频道收到 nil。
他们用循环包围 Wait 以在 cond 为真之前检查,因为在大多数情况下这是一个条件。如果您不想关闭频道中的频道守卫信令并使用锁定进行广播,这会使操作优先级确定。
func main() {
doStuffChan = make(chan bool)
cond = &sync.Cond{L: &sync.Mutex{}}
go startDoStuffLoop()
cond.L.Lock()
doStuffChan <- true
cond.Wait()
cond.L.Unlock()
fmt.Println(result)
}
func startDoStuffLoop() {
for {
<-doStuffChan
result = "success"
cond.L.Lock()
cond.Broadcast()
cond.L.Unlock()
}
}
看到它有效https://play.golang.org/p/1S6VW7nIoV但是这两个版本都是线程安全的。
我正在尝试对在无限循环上运行的通道进行单元测试。我想我已经找到了一种方法,但我不确定这是否是使用条件变量的有效方法。另外我不确定这种方法是否容易出现竞争条件。由于 for 循环在其自己的 goroutine 上是 运行,当我到达 "cond.Wait()?" 时,通道是否可能会耗尽?如果发生这种情况,我会永远挂起吗?在我见过的所有使用条件变量的示例中,它们通常伴随着一个围绕等待的 for 循环。我这里需要这个吗?我的问题:我在这里使用的方法有什么问题吗?这是valid/idiomatic条件变量的使用吗?
package main
import (
"fmt"
"sync"
)
var doStuffChan chan bool
var cond *sync.Cond
var result string
func main() {
doStuffChan = make(chan bool, 10)
cond = &sync.Cond{L: &sync.Mutex{}}
go startDoStuffLoop()
doStuffChan <- true
cond.L.Lock()
cond.Wait()
cond.L.Unlock()
fmt.Println(result)
}
func startDoStuffLoop() {
for {
<-doStuffChan
result = "success"
cond.Broadcast()
}
}
在我看来,您的所有假设都是正确的。为避免通道耗尽,只需使用
close(doStuffChan)
而不是 doStuffChan <- true
,因为您可以永远从关闭的频道收到 nil。
他们用循环包围 Wait 以在 cond 为真之前检查,因为在大多数情况下这是一个条件。如果您不想关闭频道中的频道守卫信令并使用锁定进行广播,这会使操作优先级确定。
func main() {
doStuffChan = make(chan bool)
cond = &sync.Cond{L: &sync.Mutex{}}
go startDoStuffLoop()
cond.L.Lock()
doStuffChan <- true
cond.Wait()
cond.L.Unlock()
fmt.Println(result)
}
func startDoStuffLoop() {
for {
<-doStuffChan
result = "success"
cond.L.Lock()
cond.Broadcast()
cond.L.Unlock()
}
}
看到它有效https://play.golang.org/p/1S6VW7nIoV但是这两个版本都是线程安全的。