Q:

Why goroutine channel does this?

I'm new with golang. I'm trying to understand how channels work, but it's really confusing.
I commented my questions. Can someone explain to me why this code behaves in this strange way?
package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
    c := make(chan int)
    go pokeVals(slice, c)

    fmt.Println(slice)
    fmt.Println("start")
    <-c // why 2 "poke"s here?
    fmt.Println("-")
    <-c // why 0 "poke"s?
    //<-c // But if uncommented - 2 more "pokes" here

    fmt.Println("end")
}

func pokeVals(values []int, c chan int) {
    for _, val := range values {
        fmt.Println("poke")
        c <- val
    }
    fmt.Println("overpoked")
}

Golang playground link: https://play.golang.org/p/u__cVyUbNJY

A:

Goroutines run concurrently. How they're scheduled is out of your hands, the only guarantee you get regarding to that is if you use synchronization such as channels, waitgroups or other synchronization primitives.
From main() you launch a goroutine which sends values on c in a loop. But before sending each value, it first prints "poke". So you may see one "poke" printed even if you don't receive from c. If you do receive a value from c, then the loop in this goroutine can proceed to the next iteration which again prints "poke", and it may do so immediately, even before the main() goroutine gets to printing "-". This is what you experience.
The main() goroutine in the original version (3rd <-c commented out) terminates (after printing "end"). Once main() returns, your app ends, it does not wait for other goroutines to finish. This is what you experience. For details, see No output from goroutine.
If you uncomment the 3rd <-c, then main() must wait another send on c, which means it definitely has to wait for the "poke" print before that. And once pokeVals()'s goroutine is able to send another value on c, it may print "poke" again in the loops next iteration (if this is scheduled earlier than returning from main()), which is what you experience.
Whether you see 2 additional "poke"'s printed is not deterministic, 1 or 2 of them are both valid results.

