【问题标题】:Can I reopen a closed channel?我可以重新打开已关闭的频道吗?
【发布时间】:2019-03-25 16:16:11
【问题描述】:

我想弄清楚是否可以在关闭频道后重新打开它。

测试用例:

  1. 我有一个频道,里面有一些东西
  2. 我想覆盖它们,因此我需要提前关闭通道
  3. 我想在频道中添加更多内容并再次对其进行迭代
go func() {
    queue <- "1"
    queue <- "2"
    close(queue)
}()

for i := range queue {
    go func(i string) {
        fmt.Println("From queue: ", i)
    }(i)
}

go func() {
    open(queue)
    queue <- "3"
    queue <- "4"
    close(queue)
}()

for i := range queue {
    go func(i string) {
        fmt.Println("From queue: ", i)
    }(i)
}
  • 当然open 不存在。如何在 Go 中实现我需要的东西?
  • 我不想使用睡眠功能

【问题讨论】:

  • 不,除了创建一个新频道之外,没有其他方法可以重新打开频道。
  • "我想覆盖它们,因此我需要提前关闭频道" --> 不,您不需要关闭频道。只要频道中有项目,您的循环就会运行。它只会在频道关闭时退出
  • play.golang.org/p/g2xBoM4M7up 能满足你的需要吗?
  • 要么不关闭通道,要么关闭后重新创建(make(chan string)

标签: go channel


【解决方案1】:

您无法重新打开已关闭的频道,但您可以在频道上发送channel,也许是this is what you're looking for

package main

import (
    "fmt"
    "time"
)

func main() {
    queue := make(chan chan int)
    defer close(queue)

    go func() { // reader
        for {
            ch := <-queue
            for i := range ch {
                fmt.Println(i)
            }
            fmt.Println("Done with this channel")
        }
    }()

    go func() { // writer-1
        ch := make(chan int)
        defer close(ch)
        queue <- ch
        ch <- 4
        ch <- 2
    }()

    go func() { // writer-2
        ch := make(chan int)
        defer close(ch)
        queue <- ch
        ch <- 4
        ch <- 20
    }()
    time.Sleep(time.Second)
}

【讨论】:

  • 我建议的一件事是使用等待组而不是 time.Sleep()
  • @xReprisal,是的,但这只是一个例子,当我尝试使用等待组时,我得到了something more cumbersome
【解决方案2】:

我想覆盖它们因此我需要提前关闭频道

不用,不需要关闭频道。当另一个项目通过通道推送时,它将恢复迭代。

以下代码接受控制台输入并将其推送到频道:

ma​​in.go

package main

import (
    "log"
    "bufio"
    "os"
    "fmt"
)

func process(c chan string) {
    for s := range c {
        log.Println("processed", s)
    }
}

func main() {
    c := make(chan string, 10)
    go process(c)

    // get from console and process
    reader := bufio.NewReader(os.Stdin)
    fmt.Println("INPUT STUFF. TYPE #quit TO EXIT.")
    for {
        input, _, _ := reader.ReadLine()
        if string(input) == "#quit" {
            break
        }
        c <- string(input)
    }

    log.Println("BYE!")
}

输出

INPUT STUFF. TYPE #quit TO EXIT.
hello
2018/10/23 10:43:52 processed hello
world
2018/10/23 10:43:54 processed world
#quit
2018/10/23 10:43:57 BYE!

以下示例使用 Sleep() 并且可作为 Go Playground snippet 运行

package main

import (
    "log"
    "time"
)

func process(c chan string) {
    for s := range c {
        log.Println("processed", s)
    }
}

func main() {
    c := make(chan string, 10)

    go process(c)

    // push some data
    c <- "barry allen"
    c <- "iris west"

    time.Sleep(time.Second * 2)

    // push more data
    c <- "joe west"
    c <- "caitlin snow"

    time.Sleep(time.Second * 3)
}

输出

2009/11/10 23:00:00 processed barry allen
2009/11/10 23:00:00 processed iris west
2009/11/10 23:00:02 processed joe west
2009/11/10 23:00:02 processed caitlin snow

希望这会有所帮助。干杯,

【讨论】:

  • 可以,但是我不想使用睡眠功能,我觉得它很hacky。抱歉,忘记将其添加到问题中。
  • @Jack,您不需要 使用 Sleep 它只是用来说明正在发生的事情(在我的回答中相同)。
  • 好的,你可以试试上面的编辑。改为使用命令行输入来显示process 函数会随着时间的推移而起作用。
  • 已编辑答案,因此两个样本都存在(我喜欢在 Go Playground 中拥有可运行的样本):)
  • 好的,我明白了。谢谢乔纳森。您将如何更改代码以不使用无限循环来防止程序终止?我想等待组可以做到吗?
【解决方案3】:

虽然您无法重新打开通道,但可以创建一个新通道并分配给变量。先前关闭的通道将被垃圾收集。在这种情况下,我重用了 queue 变量,但您也可以创建一个新的 queue2 变量并将其传递给 goroutine。

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    queue := make(chan int)
    go printFormat(nil, queue)
    queue <- 1
    queue <- 2
    close(queue)
    // fake some actions in between
    time.Sleep(2 * time.Second)
    queue = make(chan int)
    go printFormat(cancel, queue)
    queue <- 3
    queue <- 4
    close(queue)
    <-ctx.Done()
}

func printFormat(c context.CancelFunc, q chan int) {
    for i := range q {
        fmt.Printf("Data %d \n", i)
    }
    if c != nil {
        c()
    }
}

【讨论】:

    猜你喜欢
    • 2020-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-25
    相关资源
    最近更新 更多