2 回答
TA贡献1846条经验 获得超7个赞
您的第一个问题是:q <- true
func(c chan bool) {
for _, f := range v {
wg.Add(1)
go f(c)
}
q <- true
}(c)
将其包含在块中没有任何作用(我怀疑您在某个时候在go例程中运行它)。正如所写的,它将启动三个去例程,然后击中。由于没有任何东西接收到,这将被阻止。func()q <- trueq
修复后,您将遇到下一个问题:
p := receive(c, q)
fmt.Println(p)
wg.Wait()
receive从 或 中抓取一些东西;您可能希望从中获取三个值,然后从中获取一个值,但它同样可能(可能更有可能)从之前接收(这会导致另一个死锁)。vqvqqvwg.Wait
有几种方法可以解决这个问题;正如彼得在评论中提到的,您可以使用缓冲通道(例如);发送到被阻止的通道不会阻止,除非该通道已满。或者,我怀疑你的意图是这样的(游乐场):c := make(chan bool, len(v))
func main() {
v := []func(chan<- bool){
a1,
a2,
a3,
}
q := make(chan bool)
c := make(chan bool)
for _, f := range v {
wg.Add(1)
go f(c)
}
// When the above go routines have completed send to q
go func() {
wg.Wait()
q <- true
}()
p := receive(c, q)
fmt.Println(p)
}
正如彼得所指出的,你确实需要适应提前接纳和离开的情况。这可以通过使用缓冲通道来解决,或者您可以启动一个go例程,该例程仅转储通道上接收的数据,即:receivefalsev
case v := <-c:
if !v {
fmt.Println("Received ", v)
// Throw away anything else received on v to allow other go routines to complete
go func() { for _ = range v {}}()
return false
}
如果你采取这种方法,你需要确保最终关闭;事实上,你可以用它作为退出的信号,这可以大大简化事情:v
go func() {
wg.Wait()
close(c)
}()
这完全消除了对的需求。您的范围可以通过通道,例如)。qreceivefor v := range c {...
TA贡献1824条经验 获得超8个赞
这加起来是英国人的伟大而详细的答案。
此示例使用上下文取消来跳过写入,它总是会耗尽 。c
原始代码中的问题是,您试图通过从其出口点停止流来退出,您正在阻碍它。
正如 Brits 的回答所示,这不是停止处理流的正确方法,因为它会在管道中留下非托管数据。
一般的想法是在取消信号到达时停止将数据发送到管道(关闭输入数据源),并让管道通过完全耗尽正在进行的数据来完成其对正在进行的数据的工作。
package main
import (
"context"
"fmt"
"os"
"os/signal"
"sync"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
s := make(chan os.Signal, 10)
signal.Notify(s)
<-s
cancel()
}()
// let us simulate cancellation
go func() {
<-time.After(time.Millisecond * 200)
cancel()
}()
v := []func(context.Context, chan<- bool){
a1,
a2,
a3,
}
c := make(chan bool)
var wg sync.WaitGroup
for _, f := range v {
wg.Add(1)
f := f
go func() {
f(ctx, c)
wg.Done()
}()
}
go func() {
wg.Wait()
close(c)
}()
for v := range c {
fmt.Println("Received ", v)
}
}
func a1(ctx context.Context, c chan<- bool) {
<-time.After(time.Millisecond * 1000)
select {
case c <- true:
fmt.Println("Finish 1")
case <-ctx.Done():
fmt.Println("Cancelled 1")
}
}
func a2(ctx context.Context, c chan<- bool) {
<-time.After(time.Millisecond * 1000)
select {
case c <- true:
fmt.Println("Finish 2")
case <-ctx.Done():
fmt.Println("Cancelled 2")
}
}
func a3(ctx context.Context, c chan<- bool) {
<-time.After(time.Millisecond * 1000)
select {
case c <- true:
fmt.Println("Finish 3")
case <-ctx.Done():
fmt.Println("Cancelled 3")
}
}
最后回答问题标题Need to run several func() bool and get the first false
您可能希望实现流减少。捕获所有值,实现一个小逻辑以尽快关闭您的减排目标。但总是继续完全耗尽它。
package main
import (
"context"
"fmt"
"os"
"os/signal"
"sync"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
s := make(chan os.Signal, 10)
signal.Notify(s)
<-s
cancel()
}()
// let us simulate cancellation
go func() {
<-time.After(time.Millisecond * 200)
cancel()
}()
v := []func(context.Context, chan<- bool){
a1,
a2,
a3,
}
c := make(chan bool)
var wg sync.WaitGroup
for _, f := range v {
wg.Add(1)
f := f
go func() {
f(ctx, c)
wg.Done()
}()
}
// When the above go routines have completed send to q
go func() {
wg.Wait()
close(c)
}()
firstRes := make(chan bool)
go func() {
var closed bool
for v := range c {
if !v && !closed {
firstRes <- v
closed = true
close(firstRes)
}
fmt.Println("Received ", v)
}
if !closed {
close(firstRes)
}
}()
var wasFalsy bool
for v := range firstRes {
wasFalsy = !v
}
fmt.Println("was falsy ", wasFalsy)
}
func a1(ctx context.Context, c chan<- bool) {
<-time.After(time.Millisecond * 2000)
select {
case c <- !true:
fmt.Println("Finish 1")
case <-ctx.Done():
fmt.Println("Cancelled 1")
}
}
func a2(ctx context.Context, c chan<- bool) {
<-time.After(time.Millisecond * 2000)
select {
case c <- true:
fmt.Println("Finish 2")
case <-ctx.Done():
fmt.Println("Cancelled 2")
}
}
func a3(ctx context.Context, c chan<- bool) {
<-time.After(time.Millisecond * 2000)
select {
case c <- true:
fmt.Println("Finish 3")
case <-ctx.Done():
fmt.Println("Cancelled 3")
}
}
- 2 回答
- 0 关注
- 79 浏览
添加回答
举报