如何比较Go中渠道的价值 第一次修复removeDuplicates() 现在要修复main()

问题描述

我有两个频道,首先给我一些字符串,我需要将它们过滤为相同的值,然后将结果发送到第二个频道

func main() {
    c := make(chan string,5)
    o := make(chan string,5)
    arr := []string{"aa","ab","bb","ba","cc"}
    for _,v := range arr {
        c <- v
        go removeDuplicates(c,o)
        time.Sleep(1 * time.Second)
        fmt.Println("output: ",<-o)
    }
}

func removeDuplicates(cIn,cOut chan string) {
   last := ""
   for cur,isOpen := <-cIn; isOpen; {
      if cur != last {
        fmt.Printf("val: %s,last: %s\n",cur,last) 
        last = cur
        cOut <- cur
        //close(cOut)
      }
   }
}

我尝试将以前的值保存到“ last”变量,但是当我运行程序时,“ last”为空

val: aa,last: 
output:  aa
val: ab,last: 
output:  ab
val: ab,last:

我也不知道在这种情况下何时需要关闭哪些通道。 谢谢您的帮助和关注

解决方法

第一次修复removeDuplicates()

问题是您的for statement中有一个空的发布声明:

for cur,isOpen := <-cIn; isOpen; {
    // ..
}

因此,您从cIn渠道收到了一次,但是您再也收到不到,因此您在post语句中什么也不做,所以您无休止地重复循环主体。

一旦执行了循环主体,就必须再次接收:

for cur,isOpen := <-cIn; isOpen; cur,isOpen = <-cIn {
    // ..
}

这样,输出将是(在Go Playground上尝试):

val: aa,last: 
output:  aa
val: ab,last: aa
output:  ab
val: ab,last: 
output:  ab
val: bb,last: ab
output:  bb
val: bb,last: 
output:  bb
val: ba,last: ab
output:  ba
val: cc,last: 
output:  cc

但是最好是在频道上使用for range

for cur := range cIn {
    if cur != last {
        fmt.Printf("val: %s,last: %s\n",cur,last)
        last = cur
        cOut <- cur
    }
}

这输出相同。在Go Playground上尝试这个。

现在要修复main()

我们看到“无效”输出,输出中的值仍然重复。

这是因为您启动了多个运行removeDuplicates()的goroutine。这很不好,因为在输入通道上发送的值将被多个goroutine接收,并且如果一个重复的值未被一个接收,则仍然可以将它们检测为唯一值,因此相同的值将多次发送到输出

只有一个生产者在输入通道上发送所有值,一旦发送完所有值,就关闭通道。

只有一个goroutine使用for range来过滤值,一旦循环退出(所有输入值都被消耗),就关闭输出通道。

并且有一个goroutine使用for range从输出通道接收值,因此您可以消除丑陋的time.Sleep

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

    go func() {
        arr := []string{"aa","ab","bb","ba","cc"}
        for _,v := range arr {
            c <- v
        }
        close(c)
    }()

    go removeDuplicates(c,o)

    for v := range o {
        fmt.Println("output: ",v)
    }
}

func removeDuplicates(cIn chan string,cOut chan string) {
    last := ""
    for cur := range cIn {
        if cur != last {
            fmt.Printf("val: %s,last)
            last = cur
            cOut <- cur
        }
    }
    close(cOut)
}

这将输出(在Go Playground上尝试):

val: aa,last: 
val: ab,last: aa
val: bb,last: ab
val: ba,last: bb
val: cc,last: ba
output:  aa
output:  ab
output:  bb
output:  ba
output:  cc
,

我已注释了代码,以便您理解。请参考以下代码:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var (
        c  = make(chan string,1)
        o  = make(chan string,1)
        wg = sync.WaitGroup{}
    )

    stream := []string{"aa","cc"}

    wg.Add(1)
    // Wait until all the values are received
    defer wg.Wait()
    // Getter receives the filtered out stream
    go getter(o,&wg)

    // Removes duplicates from the stream
    go removeDuplicates(c,o)

    // Send elems to removeDuplicates
    for _,elem := range stream {
        c <- elem
    }
    // Close the channel
    close(c)
}

// getter recieves the filtered out elements
func getter(cOut <-chan string,wg *sync.WaitGroup) {
    defer wg.Done()
    for val := range cOut {
        fmt.Println("Output: ",val)
    }
}

// removeDuplicates removes the adjacent duplicates
func removeDuplicates(cIn chan string,cOut chan string) {
    var last string
    for cur := range cIn {
        if cur != last {
            fmt.Printf("val: %s,last)
            last = cur
            cOut <- cur
        }
    }
    close(cOut)
}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...