Recursion 如何在不关闭缓冲通道的情况下发现未接收到任何内容?

Recursion 如何在不关闭缓冲通道的情况下发现未接收到任何内容?,recursion,go,channel,goroutine,Recursion,Go,Channel,Goroutine,有没有办法知道通道中的所有值是否已被消耗?我正在制作一个爬虫,它递归地从种子站点获取站点。我不会关闭通道,因为它会消耗服务器的资源,并且应该在每次发送新站点时进行爬网。对于给定的种子站点,除了超时之外,我找不到更好的方法来了解子任务的完成情况。如果有一种方法可以知道通道中没有任何值(留下来使用),我的程序可以退出子任务并继续侦听服务器。没有“在无缓冲通道中排队”之类的事情。如果通道是无缓冲的,根据定义它总是空的。如果它是缓冲的,那么它可能有一些元素在它的大小。但试图了解其中有多少元素总是会导致比

有没有办法知道通道中的所有值是否已被消耗?我正在制作一个爬虫,它递归地从种子站点获取站点。我不会关闭通道,因为它会消耗服务器的资源,并且应该在每次发送新站点时进行爬网。对于给定的种子站点,除了超时之外,我找不到更好的方法来了解子任务的完成情况。如果有一种方法可以知道通道中没有任何值(留下来使用),我的程序可以退出子任务并继续侦听服务器。

没有“在无缓冲通道中排队”之类的事情。如果通道是无缓冲的,根据定义它总是空的。如果它是缓冲的,那么它可能有一些元素在它的大小。但试图了解其中有多少元素总是会导致比赛条件,所以不要这样设计(在围棋中也是不可能的)

理想情况下,避免设计需要知道孩子什么时候完成,但当你必须完成时,给他们一个频道,让他们对你做出回应。当他们回应时,你就知道他们是完整的

你所描述的问题在围棋博客和演讲中都有详细介绍:


没有“在无缓冲通道中排队”这样的事情。如果通道是无缓冲的,根据定义它总是空的。如果它是缓冲的,那么它可能有一些元素在它的大小。但试图了解其中有多少元素总是会导致比赛条件,所以不要这样设计(在围棋中也是不可能的)

理想情况下,避免设计需要知道孩子什么时候完成,但当你必须完成时,给他们一个频道,让他们对你做出回应。当他们回应时,你就知道他们是完整的

你所描述的问题在围棋博客和演讲中都有详细介绍:


您可以通过在
select
语句中使用
default
来确定一个goroutine是否在通道的另一端被阻塞。例如:

package main

import (
    "fmt"
    "time"
)

var c = make(chan int)

func produce(i int) {
    c <- i
}

func consume() {
    for {
        select {
        case i := <-c:
            fmt.Println(i)
        default:
            return
        }
    }
}

func main() {
    for i := 0; i < 10; i++ {
        go produce(i)
    }
    time.Sleep(time.Millisecond)
    consume()
}
这会给你的制作人一秒钟的时间来产生另一个价值,但你最好使用终值。将要发送的内容包装到结构中:

type message struct {
    err error
    data theOriginalType
}
把那东西送过去。然后使用
io.EOF
或自定义错误
var Done=errors.New(“Done”)
发出完成信号

既然你有一个递归问题,为什么不使用一个?每次启动新任务时,增加等待组,每次任务完成时,减少等待组。然后有一个外部任务等待完成。例如,这里有一种非常低效的计算斐波那契数的方法:

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func fib(c chan int, n int) {
    defer wg.Done()
    if n < 2 {
        c <- n
    } else {
        wg.Add(2)
        go fib(c, n - 1)
        go fib(c, n - 2)
    }
}

func main() {
    wg.Add(1)
    c := make(chan int)
    go fib(c, 18)
    go func() {
        wg.Wait()
        close(c)
    }()
    sum := 0
    for i := range c {
        sum += i
    }
    fmt.Println(sum)
}
主程序包
进口(
“fmt”
“同步”
)
var wg sync.WaitGroup
func fib(c chan int,n int){
推迟工作组完成()
如果n<2{

c您可以通过在
select
语句中使用
default
来确定是否在通道的另一端阻止goroutine。例如:

package main

import (
    "fmt"
    "time"
)

var c = make(chan int)

func produce(i int) {
    c <- i
}

func consume() {
    for {
        select {
        case i := <-c:
            fmt.Println(i)
        default:
            return
        }
    }
}

func main() {
    for i := 0; i < 10; i++ {
        go produce(i)
    }
    time.Sleep(time.Millisecond)
    consume()
}
这会给你的制作者一秒钟的时间来产生另一个值,但你最好使用一个终值。将你在结构中发送的内容包装起来:

type message struct {
    err error
    data theOriginalType
}
然后使用
io.EOF
或自定义错误
var Done=errors.New(“Done”)
来表示完成

既然存在递归问题,为什么不使用?每次启动新任务时,等待组都会增加,每次任务完成时,等待组都会减少。然后让外部任务等待完成。例如,下面是一种计算斐波那契数的非常低效的方法:

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func fib(c chan int, n int) {
    defer wg.Done()
    if n < 2 {
        c <- n
    } else {
        wg.Add(2)
        go fib(c, n - 1)
        go fib(c, n - 2)
    }
}

func main() {
    wg.Add(1)
    c := make(chan int)
    go fib(c, 18)
    go func() {
        wg.Wait()
        close(c)
    }()
    sum := 0
    for i := range c {
        sum += i
    }
    fmt.Println(sum)
}
主程序包
进口(
“fmt”
“同步”
)
var wg sync.WaitGroup
func fib(c chan int,n int){
推迟工作组完成()
如果n<2{
C