šŸ‘©šŸ»ā€šŸ’»Study Log_Go_Goroutine_Channel

HAYEON SONHAYEON SON
3 min read

GoRoutine & Channel

A goroutine is a lightweight thread managed by the Go runtime. You can just put ā€˜go’ in front of the function you want to run concurrently. Also, you can create channel that receives from goroutine to see if it finishes without any issues or to communicate cross goroutines.

Then, let’s compare how fast a for loop is versus using a goroutine.

Let’s say we have a function to get a response for each website with http.Get function. (URLChecker)

If we use typical for loop to call the function and printing out the result after putting them to a map, it took 3.116982042s.

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    start := time.Now()
    results := make(map[string]string)

    urls := []string{
        "https://www.airbnb.com/",
        "https://www.google.com/",
        "https://www.amazon.com/",
        "https://www.reddit.com/",
        "https://www.facebook.com/",
        "https://www.instagram.com/",
    }

    for _, url := range urls {
        result := hitURLFor(url)
        results[url] = result
    }

    for url, status := range results {
        fmt.Println(url, status)
    }
    elapsed := time.Since(start)
    fmt.Printf("Execution time: %s\n", elapsed)

}

func hitURLFor(url string) string {
    resp, err := http.Get(url)
    status := "OK"
    if err != nil || resp.StatusCode >= 400 {
        status = "FAILED"
    }
    return status
}

Then, Let’s try goroutine. The code is below and it took only 493.601917ms. 🫢

package main

import (
    "fmt"
    "net/http"
    "time"
)

type requestResult struct {
    url    string
    status string // ok or failed
}

func main() {
    start := time.Now()
    results := make(map[string]string)
    c := make(chan requestResult)
    urls := []string{
        "https://www.airbnb.com/",
        "https://www.google.com/",
        "https://www.amazon.com/",
        "https://www.reddit.com/",
        "https://www.facebook.com/",
        "https://www.instagram.com/",
    }
    for _, url := range urls {
        go hitURL(url, c)
    }

    for i := 0; i < len(urls); i++ {
        //fmt.Println(<-c) // printing messages from channels
        result := <-c
        results[result.url] = result.status
    }

    for url, status := range results {
        fmt.Println(url, status)
    }

    elapsed := time.Since(start)
    fmt.Printf("Execution time: %s\n", elapsed)

}

func hitURL(url string, c chan<- requestResult) {
    // <- this channel will be send only
    //fmt.Println("Checking:", url)
    resp, err := http.Get(url)
    status := "OK"
    if err != nil || resp.StatusCode >= 400 {
        status = "FAILED"
    }
    c <- requestResult{url: url, status: status}
}

How could this be so fast and what’s going on behind the scene?

As mentioned earlier, goroutines allow jobs to run concurrently, unlike a for-loop, enabling tasks complete much faster. However, if the main function returns before the goroutines finish, they will be terminated. Therefore, we need channels to notify the main function that goroutines are still running.

We can create a channel as shown below and use it to return a struct-type value, requestResult (which contains a URL and status). You may notice some arrows (←, →); these indicate the direction of communication—whether the channel is being used for sending or receiving data.

For example:

  • c chan← requestResult means "send a requestResult value to channel c."

  • result := ←c means "receive a value from channel c and assign it to the variable result."

Also, if you look at the argument of the hitURL function, it has c chan← requestResult. We can also write this as c chan requestResult without the ← because chan requestResult already implies that it's a channel for that type. However, adding ← explicitly indicates that the channel is send-only.

c := make(chan requestResult)

GoLang Tutorials for Beginners | Go Concurrency & Routines | Go Routine  Channels

More details : https://go.dev/ref/mem#chan

0
Subscribe to my newsletter

Read articles from HAYEON SON directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

HAYEON SON
HAYEON SON