Whats wrong with my channel

111 views
Skip to first unread message

Денис Мухортов

unread,
Aug 19, 2021, 10:43:32 AM8/19/21
to golang-nuts
I just started practicing with channels, after writing to the channel, nothing is output from there
func main() {
    d := make(chan int)
    go factorial(5, d)
     time.Sleep(3 * time.Second)
}

func factorial(n int, d chan int) {
    fmt.Println("function starting...")
    time.Sleep(3 * time.Second)
    var a int = 1
    for ; n > 0; n-- {
        a *= n
    }
    d <- a // //nothing works after that
    fmt.Println(<-d)
    fmt.Println(a)
}
--------------------------------------------------------------------------------------------------------------------------------------------
Another question I want to make a recursive function with a factorial, pass it to goroutine in main. But I do not know if it is possible to somehow combine *return* and a channel in the declaration of arguments.
---------------------------------------------------------------------------------------------------------------------------------------------
if I first pass in something to the channel from main,
a lock occurs.Why? So it's not possible at all?

Jan Mercl

unread,
Aug 19, 2021, 10:58:54 AM8/19/21
to Денис Мухортов, golang-nuts
On Thu, Aug 19, 2021 at 4:43 PM Денис Мухортов
<muhorto...@gmail.com> wrote:

> I just started practicing with channels, after writing to the channel, nothing is output from there
> func main() {
> d := make(chan int)
> go factorial(5, d)
> time.Sleep(3 * time.Second)
> }
>
> func factorial(n int, d chan int) {
> fmt.Println("function starting...")
> time.Sleep(3 * time.Second)
> var a int = 1
> for ; n > 0; n-- {
> a *= n
> }
> d <- a // //nothing works after that
> fmt.Println(<-d)
> fmt.Println(a)
> }

Your main function can and probably does just return before the write
to d in factorial is performed. When the main function returns, the
process exits.

I suggest never to use time.Sleep as a synchronization mechanism. Not
even in experiments or throw away code. It may sometimes work, but it
is probably never correct. In either case, it makes reasoning about
the code hard, if not impossible, so proper synchronization is much
better for your understanding when you're "practicing with channels".

-j

jake...@gmail.com

unread,
Aug 19, 2021, 11:35:16 AM8/19/21
to golang-nuts
Jan is correct, and you should probably use a sync.WaitGroup to keep your main() alive.

But even if you do that, you have a bigger problem. You channel is unbuffered. That means that `d <- a` will block until someone reads from d. Since `factorial` is the only goroutine that uses d, that line will block forever. (Of course, in your code, main() will exit after 3 seconds, so forever is short.) You can 'fix' the code by changing to a buffered channel, like: `d := make(chan int, 1)`. Then your code works, since the send will no longer block. Although it is pretty pointless to read from a channel in the same goroutine that writes to it.

A more common use would be for the goroutine to send the result back to main, like this: https://play.golang.org/p/yJHJWhYif5h
Note that, in this case, the channel read keeps main() from exiting before factorial() is finished.

Roland Müller

unread,
Aug 19, 2021, 2:47:52 PM8/19/21
to jake...@gmail.com, golang-nuts
Here is a sleepless version. The channel is still unbuffered, but this should be OK since reading from channel is done in main().
Thus, factorial() writes the result to the channel, and main() reads it from there. As result main() does not end before factorial() is completed.

package main
import (
    "fmt"
)


func main() {
    d := make(chan int)
    go factorial(5, d)
    fmt.Println("waiting ...")
    fmt.Println(<-d)
    fmt.Println("Game over", d)

}

func factorial(n int, d chan int) {
    fmt.Println("function starting...")
    var a int = 1
    for ; n > 0; n-- {
        a *= n
    }
    fmt.Println("result=", a)
    d <- a
}




--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/e81505fe-3415-4eb0-acf0-4b208e42fa13n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages