我跟随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
是正确的方法选择range
中的频道。这是对的吗?
更新
好的,我已经删除了我的代码中的剩余问题,现在当我尝试编译时,我收到错误消息:
url evaluated but not used
select case must be receive, send or assign recv
答案 0 :(得分:0)
我不完全理解
case out <- n * n
行:我可以看到它说如果有n的值,那么将它平方并将其发送到频道,但我不明白为什么。
这不正确。 case out <- n * n
检查out
是否已准备好阅读,并n * n
发送给out
(如果是)。除非done
也准备就绪。
select
。无论哪个频道准备就绪,它都会做到这一点。如果准备好多个频道,它将随机选择一个频道。
select {
case out <- n * n:
case <-done:
return
}
}
这会选择out
和done
。如果其中任何一个准备好继续,即。 out
已准备好阅读或有done
的内容,它会选择其中一个案例。订单是随机的,因此即使从out
读取内容,也可以向done
发送更多内容。
此模式用于关闭无限的goroutine。如果你停止从它的输出通道读取它,它将不再做任何工作,但它会在内存中徘徊。因此,通过将值传递给done
,您可以告诉goroutine关闭。
UPDATE :在原始情况下,goroutine在输入通道上循环并发送输出,done
是不必要的复杂功能。关闭输入通道后,该功能将返回。
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
}
答案 1 :(得分:0)
加入* {
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
background-color: #8799b7;
overflow-y: scroll;
max-height: 735px;
}
.header {
display: block;
background-image: url("header4.jpg");
height: 500px;
}
.home_page {
display: flex;
margin:0;
padding: 0;
}
.home_page > div {
border: 1px solid grey;
}
.home_left {
height: 235px;
width: 506px;
margin: 0;
padding: 0;
}
.home_center {
height: 235px;
width: 506px;
margin: 0;
padding: 0;
}
.home_right {
height: 235px;
width: 506px;
margin: 0;
padding: 0;
}
或不会对range
在此处所做的事情产生任何影响。
不,select
没有采用第一个真正的表达式......它根本不采用表达式。唯一可以表达为表达式的东西是频道发送,频道接收和带右侧的频道接收分配。
select
说“如果可以发送select {
case out <- n * n:
case <-done:
return
}
(即它有剩余容量或有效阅读器),则将值out
发送给它并继续。如果从n * n
收到,则可能,从函数返回。如果两者都可以,那么随机选择一个并执行。如果两者都不可能,请等到其中一个成为可能。“ (请参阅规范中的Select Statements)。
如果需要计算要发送的值(并且它太复杂而无法放在频道发送的右侧),只需在done
之前执行即可。该规范清楚地表明,select中send语句中的所有表达式都是提前计算的,因此不会丢失任何内容。