在 go 通道上选择内部范围
Selecting inside range over go channel
我正在关注 this post 以并行化我的应用程序。我需要定制这段代码:
func sq(done <-chan struct{}, in <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for n := range in {
select {
case out <- n * n:
case <-done:
return
}
}
}()
return out
}
我不完全理解 case out <- n * n:
行。我可以看到它是说如果 n
有一个值,然后将它平方并发送到通道,但我不明白为什么。 select
是否只接受第一个 true
案例?能否改写:
for n := range in {
select {
case n:
out <- n * n
case <-done:
return
}
}
无论如何,我需要用函数调用替换行 case out <- n * n:
。我已将其更改为以下内容:
out := make(chan structs.Ticket)
go func() {
defer close(out)
for url := range inputChannel {
select {
case url:
data, err := GetData(url)
fmt.Println("Got error: ", err)
out <- data
case <-done:
return
}
}
}()
return out
看起来这会编译(我还不能编译它),但是因为调试并行代码并不简单我想检查使用 case url
是否是 [=36= 的正确方法] 在 range
的一个频道上。这样对吗?
更新
好的,我已经删除了代码中的剩余问题,现在当我尝试编译时,我收到了错误消息:
url evaluated but not used
select case must be receive, send or assign recv
I don't fully understand the line case out <- n * n
:. I can see it's saying that if there's a value for n, then square it and send it down the channel, but I don't understand why.
这是不正确的。 case out <- n * n
检查 out
是否准备好读取,如果准备就绪则发送 n * n
到 out
。除非done
也准备好了。
select
当您有多个频道可以通话时使用。无论哪个通道准备就绪,它都会执行该操作。如果有多个通道就绪,它会 select 随机一个。
select {
case out <- n * n:
case <-done:
return
}
}
这将 select 超过 out
和 done
。如果任何一个准备好继续,即。 out
已准备好阅读或 done
有内容可读,它将选择其中一种情况。顺序是随机的,因此即使 done
.
有内容需要读取,也可以发送更多 out
此模式用于关闭无限协程。如果你停止从它的输出通道读取,它就不会再做任何工作,但它会在内存中徘徊。因此,通过将值传递给 done
,您可以告诉 goroutine 关闭。
UPDATE:在您原来的情况下,goroutine 在输入通道上循环并发送输出,done
是不必要的并发症。输入通道关闭后,函数将 return.
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for n := range in {
out <- n * n
}
}()
return out
}
func main() {
in := make(chan int)
out := sq(in)
for _,i := range []int{1,2,3,4} {
in <- i
fmt.Println(<-out)
}
// The `range` inside the goroutine from sq() will exit,
// and the goroutine will return.
close(in)
}
如果它只是吐出一组不断增加的正方形,那么 done
在无限循环中是必要的。
func sq(done chan bool) <-chan int {
out := make(chan int)
go func() {
defer close(out)
n := 0
for {
select {
case <-done:
return
case out<-n*n:
n++
}
}
}()
return out
}
func main() {
done := make(chan bool)
out := sq(done)
for range []int{1,2,3,4} {
fmt.Println(<-out)
}
// The switch in the goroutine will be able to read
// from done (out's buffer being already full) and return.
done <- true
}
是否在 range
中对 select
在这里所做的事情没有任何影响。
不,select
不采用第一个真表达式...它根本不采用表达式。唯一可以作为表达式的情况出现的是通道发送、通道接收和右侧带有通道接收的分配。
select {
case out <- n * n:
case <-done:
return
}
说 "if sending on out
is possible (i.e. it has remaining capacity or an active reader), then send the value n * n
to it and continue. If receiving from done
is possible, return from the function. If both are possible, choose one at random and do it. If neither is possible, wait until one of them becomes possible."(参见规范中的 Select Statements)。
如果您要发送的值需要计算(并且它太复杂而无法放在通道发送的右侧),只需在 select
之前执行即可。规范清楚地表明,select 中发送语句中的所有表达式都是提前计算的,因此不会丢失任何内容。
我正在关注 this post 以并行化我的应用程序。我需要定制这段代码:
func sq(done <-chan struct{}, in <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for n := range in {
select {
case out <- n * n:
case <-done:
return
}
}
}()
return out
}
我不完全理解 case out <- n * n:
行。我可以看到它是说如果 n
有一个值,然后将它平方并发送到通道,但我不明白为什么。 select
是否只接受第一个 true
案例?能否改写:
for n := range in {
select {
case n:
out <- n * n
case <-done:
return
}
}
无论如何,我需要用函数调用替换行 case out <- n * n:
。我已将其更改为以下内容:
out := make(chan structs.Ticket)
go func() {
defer close(out)
for url := range inputChannel {
select {
case url:
data, err := GetData(url)
fmt.Println("Got error: ", err)
out <- data
case <-done:
return
}
}
}()
return out
看起来这会编译(我还不能编译它),但是因为调试并行代码并不简单我想检查使用 case url
是否是 [=36= 的正确方法] 在 range
的一个频道上。这样对吗?
更新
好的,我已经删除了代码中的剩余问题,现在当我尝试编译时,我收到了错误消息:
url evaluated but not used
select case must be receive, send or assign recv
I don't fully understand the line
case out <- n * n
:. I can see it's saying that if there's a value for n, then square it and send it down the channel, but I don't understand why.
这是不正确的。 case out <- n * n
检查 out
是否准备好读取,如果准备就绪则发送 n * n
到 out
。除非done
也准备好了。
select
当您有多个频道可以通话时使用。无论哪个通道准备就绪,它都会执行该操作。如果有多个通道就绪,它会 select 随机一个。
select {
case out <- n * n:
case <-done:
return
}
}
这将 select 超过 out
和 done
。如果任何一个准备好继续,即。 out
已准备好阅读或 done
有内容可读,它将选择其中一种情况。顺序是随机的,因此即使 done
.
out
此模式用于关闭无限协程。如果你停止从它的输出通道读取,它就不会再做任何工作,但它会在内存中徘徊。因此,通过将值传递给 done
,您可以告诉 goroutine 关闭。
UPDATE:在您原来的情况下,goroutine 在输入通道上循环并发送输出,done
是不必要的并发症。输入通道关闭后,函数将 return.
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for n := range in {
out <- n * n
}
}()
return out
}
func main() {
in := make(chan int)
out := sq(in)
for _,i := range []int{1,2,3,4} {
in <- i
fmt.Println(<-out)
}
// The `range` inside the goroutine from sq() will exit,
// and the goroutine will return.
close(in)
}
如果它只是吐出一组不断增加的正方形,那么 done
在无限循环中是必要的。
func sq(done chan bool) <-chan int {
out := make(chan int)
go func() {
defer close(out)
n := 0
for {
select {
case <-done:
return
case out<-n*n:
n++
}
}
}()
return out
}
func main() {
done := make(chan bool)
out := sq(done)
for range []int{1,2,3,4} {
fmt.Println(<-out)
}
// The switch in the goroutine will be able to read
// from done (out's buffer being already full) and return.
done <- true
}
是否在
range
中对select
在这里所做的事情没有任何影响。不,
select
不采用第一个真表达式...它根本不采用表达式。唯一可以作为表达式的情况出现的是通道发送、通道接收和右侧带有通道接收的分配。select { case out <- n * n: case <-done: return }
说 "if sending on out
is possible (i.e. it has remaining capacity or an active reader), then send the value n * n
to it and continue. If receiving from done
is possible, return from the function. If both are possible, choose one at random and do it. If neither is possible, wait until one of them becomes possible."(参见规范中的 Select Statements)。
如果您要发送的值需要计算(并且它太复杂而无法放在通道发送的右侧),只需在 select
之前执行即可。规范清楚地表明,select 中发送语句中的所有表达式都是提前计算的,因此不会丢失任何内容。