<commit_before>package main

import (
    "fmt"
    "time"
    "math/rand"
)

func main() {
    goroutines()
    blockingChannels()
    bufferedChannels()
    channelsWithRangeAndClose()
    channelsWithSelect()
}

func toBeGoroutined(i int) {
    time.Sleep(1 * time.Second)
    fmt.Println("Goroutine", i)
}

func goroutines() {
    fmt.Println("Goroutines")
    fmt.Println("==========")

    start := time.Now()

    for i := 0 ; i < 20 ; i++ {
        go toBeGoroutined(i)
    }

    fmt.Println("Starting up all goroutines took", time.Since(start))

    // Wait for all our goroutines to finish. There are better ways to do this, but that comes with channels...
    time.Sleep(2 * time.Second)

    fmt.Println()
}

func summation(c chan int, n int) {
    time.Sleep(1 * time.Second)
    c <- (n * (n + 1) / 2)
}

func blockingChannels() {
    fmt.Println("Blocking channels")
    fmt.Println("=================")

    // This is a blocking channel. Sends or receives to this channel will block until the other side is ready.
    sumChannel := make(chan int)

    // Creating a job to do a summation
    fmt.Println("Starting summation job.")
    go summation(sumChannel, 15)
    fmt.Println("Waiting for job to complete.")
    // Seeing as we created a blocking channel, the statement below will block until the answer comes back.
    fmt.Println("The summation from 1 to 15 is", <- sumChannel)

    // Go will detect when all threads are deadlocked.
    //<- sumChannel
    //sumChannel <- 1

    // And yes, you can totally use a channel as a threadsafe queue.

    fmt.Println()
}

func bufferedChannels() {
    fmt.Println("Buffered channels")
    fmt.Println("=================")

    // Buffered channels block for a send when they are full or a receive when they are empty.
    bufferedChannel := make(chan int, 2)

    bufferedChannel <- 1
    bufferedChannel <- 2
    //bufferedChannel <- 3

    fmt.Println("Channel item is", <- bufferedChannel)
    fmt.Println("Channel item is", <- bufferedChannel)
    //fmt.Println("Channel item is", <- bufferedChannel)

    fmt.Println()
}
func runThenClose(c chan int) {
    for i := 0 ; i < 10 ; i++ {
        c <- rand.Intn(100)
    }

    // Only the sender should close
    close(c);

    // A channel send after a close will result in a panic
    //c <- 1
}

func channelsWithRangeAndClose() {
    fmt.Println("Channels, range, and close")
    fmt.Println("==========================")

    rand.Seed(time.Now().UnixNano())
    c := make(chan int)

    go runThenClose(c)

    for i := range c {
        fmt.Println("Received channel value", i)
    }

    fmt.Println()
}

func channelsWithSelect() {
    fmt.Println("Channels and select")<commit_msg>Adding info on chan direction to channel example.<commit_after>package main

import (
    "fmt"
    "time"
    "math/rand"
)

func main() {
    goroutines()
    blockingChannels()
    bufferedChannels()
    channelsWithRangeAndClose()
    channelsWithSelect()
}

func toBeGoroutined(i int) {
    time.Sleep(1 * time.Second)
    fmt.Println("Goroutine", i)
}

func goroutines() {
    fmt.Println("Goroutines")
    fmt.Println("==========")

    start := time.Now()

    for i := 0 ; i < 20 ; i++ {
        go toBeGoroutined(i)
    }

    fmt.Println("Starting up all goroutines took", time.Since(start))

    // Wait for all our goroutines to finish. There are better ways to do this, but that comes with channels...
    time.Sleep(2 * time.Second)

    fmt.Println()
}

func summation(c chan int, n int) {
    time.Sleep(1 * time.Second)
    c <- (n * (n + 1) / 2)
}

func blockingChannels() {
    fmt.Println("Blocking channels")
    fmt.Println("=================")

    // This is a blocking channel. Sends or receives to this channel will block until the other side is ready.
    sumChannel := make(chan int)

    // Creating a job to do a summation
    fmt.Println("Starting summation job.")
    go summation(sumChannel, 15)
    fmt.Println("Waiting for job to complete.")
    // Seeing as we created a blocking channel, the statement below will block until the answer comes back.
    fmt.Println("The summation from 1 to 15 is", <- sumChannel)

    // Go will detect when all threads are deadlocked.
    //<- sumChannel
    //sumChannel <- 1

    // And yes, you can totally use a channel as a threadsafe queue.

    fmt.Println()
}

func bufferedChannels() {
    fmt.Println("Buffered channels")
    fmt.Println("=================")

    // Buffered channels block for a send when they are full or a receive when they are empty.
    bufferedChannel := make(chan int, 2)

    bufferedChannel <- 1
    bufferedChannel <- 2
    //bufferedChannel <- 3

    fmt.Println("Channel item is", <- bufferedChannel)
    fmt.Println("Channel item is", <- bufferedChannel)
    //fmt.Println("Channel item is", <- bufferedChannel)

    fmt.Println()
}

// You can specify the direction a channel variable will work
func runThenClose(c chan<- int) {
    for i := 0 ; i < 10 ; i++ {
        c <- rand.Intn(100)
    }

    // Only the sender should close
    close(c);

    // A channel send after a close will result in a panic
    //c <- 1
}

func channelsWithRangeAndClose() {
    fmt.Println("Channels, range, and close")
    fmt.Println("==========================")

    rand.Seed(time.Now().UnixNano())
    c := make(chan int)

    go runThenClose(c)

    for i := range c {
        fmt.Println("Received channel value", i)
    }

    fmt.Println()
}

func channelsWithSelect() {
    fmt.Println("Channels and select")
{'fraction_non_alphanumeric': 0.14311561425728242, 'fraction_numerical': 0.00904649900488511, 'mean_word_length': 2.75033921302578, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1974596', 'n_tokens_mistral': 1855, 'n_tokens_neox': 1677, 'n_words': 560}