簡體   English   中英

如何比較 Go 中通道的值

[英]how comparing value from channel in Go

我有兩個通道,首先給我一些字符串,我需要過濾到相同的值,然后結果需要發送到第二個通道

func main() {
    c := make(chan string, 5)
    o := make(chan string, 5)
    arr := []string{"aa", "ab", "ab", "bb", "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語句中有一個空的 post語句

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 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", "ab", "bb", "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: %s\n", cur, 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", "ab", "ab", "bb", "bb", "ba", "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: %s\n", cur, last)
            last = cur
            cOut <- cur
        }
    }
    close(cOut)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM