Home > Enterprise >  How to close the channel in a concurrent operation?
How to close the channel in a concurrent operation?

Time:09-26

I wrote a go code like that about concurrency and channels ⤵️

package main

import (
    "fmt"
    "net/http"
)

var links = []string{
    "https://mcevik.com",
    "https://stackoverflow.com",
    "https://www.linkedin.com",
    "https://github.com",
    "https://medium.com",
    "https://kaggle.com",
}

func getLink(link string, ch chan string) {
    if res, err := http.Get(link); err != nil {
        ch <- err.Error()
    } else {
        ch <- fmt.Sprintf("[%d] - %s", res.StatusCode, link)
    }
}

func main() {
    ch := make(chan string, len(links))

    for _, link := range links {
        go getLink(link, ch)
    }

    for msg := range ch {
        fmt.Println(msg)
    }
}

output


In the output we see that the program is not terminated. The reason for the program's not terminated is that the channel has not closed and therefore cannot exit the loop.

How can I close the channel and fix the code?

CodePudding user response:

If you start exactly N (ie len(links)) Go routines, all of which will necessarily send back a message, then the simplest thing is to read exactly N messages from the channel before closing it.

Don't range over the channel; that's most useful when you don't know how many items you'll receive and you want to read until the channel is closed. Instead loop a given number of times:

// main:

for _ = range links {
    fmt.Println(<-ch)
}

close(ch)

CodePudding user response:

use a WaitGroup to watch for writes completion.

    ch := make(chan string, len(links))
    var wg sync.WaitGroup
    for _, link := range links {
        wg.Add(1)
        go func(){
            getLink(link, ch)
            wg.Done()
        }()
    }

Use another routine to listen that event and close the channel.

    go func(){
        wg.Wait()
        close(ch)
    }()
    for msg := range ch {
        fmt.Println(msg)
    }
  • Related