golang 字符串通道 send/receive 不一致
golang string channel send/receive inconsistency
新的。我正在使用 1.5.1。我正在尝试根据传入频道积累单词列表。但是,我的输入通道 (wdCh) 在测试期间有时会得到空字符串 ("")。我很困惑。在将空字符串的累积计数添加到我的地图之前,我宁愿不对它进行测试。对我来说感觉像是黑客攻击。
package accumulator
import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)
var words map[string]int
func Accumulate(wdCh chan string, closeCh chan bool) {
words = make(map[string]int)
for {
select {
case word := <-wdCh:
fmt.Printf("word = %s\n", word)
words[word]++
case <-closeCh:
return
}
}
}
func pushWords(w []string, wdCh chan string) {
for _, value := range w {
fmt.Printf("sending word = %s\n", value)
wdCh <- value
}
close(wdCh)
}
func TestAccumulate(t *testing.T) {
sendWords := []string{"one", "two", "three", "two"}
wMap := make(map[string]int)
wMap["one"] = 1
wMap["two"] = 2
wMap["three"] = 1
wdCh := make(chan string)
closeCh := make(chan bool)
go Accumulate(wdCh, closeCh)
pushWords(sendWords, wdCh)
closeCh <- true
close(closeCh)
assert.Equal(t, wMap, words)
}
查看这篇关于 channel-axioms 的文章。看起来在 closeCh
通道上关闭 wdCh
和发送 true 之间存在竞争。
因此结果取决于在 pushWords
returning 和 Accumulate
之间首先安排的内容。
如果先 TestAccumulate
运行s,在 closeCh
上发送 true,然后当 Accumulate
运行s 它选择两个通道中的一个,因为它们都可以是 运行 因为 pushWords
关闭 wdCh
.
A receive from a closed channel returns the zero value immediately.
直到closedCh
发出信号,Accumulate
会在地图中随机放置一个或多个空的“”字。
如果先是 Accumulate
运行s 那么它可能会在词映射中放置许多空字符串,因为它循环直到 TestAccumulate
运行s 最后它发送一个closeCh
.
发出信号
一个简单的解决方法是移动
close(wdCh)
在 closeCh
上发送 true
之后。这样 wdCh
不能 return 零值,直到你在 closeCh
上发出信号。此外,closeCh <- true
阻塞是因为 closeCh
没有缓冲区大小,因此 wdCh
不会关闭,直到您保证 Accumulate
永远完成循环。
我认为原因是当你关闭频道时,"select"虽然会收到信号。
因此,当您在 "func pushWords" 中关闭 "wdCh" 时,Accumulate 中的循环将接收来自“<-wdCh”的信号。
可能您应该添加一些代码来测试通道关闭后的操作!
for {
select {
case word, ok := <-wdCh:
if !ok {
fmt.Println("channel wdCh is closed!")
continue
}
fmt.Printf("word = %s\n", word)
words[word]++
case <-closeCh:
return
}
}
新的。我正在使用 1.5.1。我正在尝试根据传入频道积累单词列表。但是,我的输入通道 (wdCh) 在测试期间有时会得到空字符串 ("")。我很困惑。在将空字符串的累积计数添加到我的地图之前,我宁愿不对它进行测试。对我来说感觉像是黑客攻击。
package accumulator
import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)
var words map[string]int
func Accumulate(wdCh chan string, closeCh chan bool) {
words = make(map[string]int)
for {
select {
case word := <-wdCh:
fmt.Printf("word = %s\n", word)
words[word]++
case <-closeCh:
return
}
}
}
func pushWords(w []string, wdCh chan string) {
for _, value := range w {
fmt.Printf("sending word = %s\n", value)
wdCh <- value
}
close(wdCh)
}
func TestAccumulate(t *testing.T) {
sendWords := []string{"one", "two", "three", "two"}
wMap := make(map[string]int)
wMap["one"] = 1
wMap["two"] = 2
wMap["three"] = 1
wdCh := make(chan string)
closeCh := make(chan bool)
go Accumulate(wdCh, closeCh)
pushWords(sendWords, wdCh)
closeCh <- true
close(closeCh)
assert.Equal(t, wMap, words)
}
查看这篇关于 channel-axioms 的文章。看起来在 closeCh
通道上关闭 wdCh
和发送 true 之间存在竞争。
因此结果取决于在 pushWords
returning 和 Accumulate
之间首先安排的内容。
如果先 TestAccumulate
运行s,在 closeCh
上发送 true,然后当 Accumulate
运行s 它选择两个通道中的一个,因为它们都可以是 运行 因为 pushWords
关闭 wdCh
.
A receive from a closed channel returns the zero value immediately.
直到closedCh
发出信号,Accumulate
会在地图中随机放置一个或多个空的“”字。
如果先是 Accumulate
运行s 那么它可能会在词映射中放置许多空字符串,因为它循环直到 TestAccumulate
运行s 最后它发送一个closeCh
.
一个简单的解决方法是移动
close(wdCh)
在 closeCh
上发送 true
之后。这样 wdCh
不能 return 零值,直到你在 closeCh
上发出信号。此外,closeCh <- true
阻塞是因为 closeCh
没有缓冲区大小,因此 wdCh
不会关闭,直到您保证 Accumulate
永远完成循环。
我认为原因是当你关闭频道时,"select"虽然会收到信号。
因此,当您在 "func pushWords" 中关闭 "wdCh" 时,Accumulate 中的循环将接收来自“<-wdCh”的信号。 可能您应该添加一些代码来测试通道关闭后的操作!
for {
select {
case word, ok := <-wdCh:
if !ok {
fmt.Println("channel wdCh is closed!")
continue
}
fmt.Printf("word = %s\n", word)
words[word]++
case <-closeCh:
return
}
}