0

The main go routine places a ball on a channel. The player goroutine gets the ball, manipulates it, then places the ball back on the channel and loops. At this point it stalls.

Why does the player goroutine stall? Shouldn't it be able to pick up the "ball" from itself? Sorry if this is staring me right in the face, but my understanding of golang concurrency leads me to believe the player go routine should be able to play ping pong all by itself.

type Ball struct{ hits int }


func main() {
    table := make(chan *Ball)
    go player("pong", table)

    table <- new(Ball) // game on; toss the ball
    time.Sleep(1 * time.Second)
    <-table // game over; grab the ball
}

func player(name string, table chan *Ball) {
    for {

        ball := <-table
        ball.hits++
        fmt.Println(name, ball.hits)
        time.Sleep(100 * time.Millisecond)
        table <- ball
    }
}

1 Answers1

4

It does not stall.
It just exits.

That is because the player, when sending back the Ball, will have to wait for the main routine to pick it up.
And once the main routine has received the ball... it exits.
That interrupts all current goroutine, meaning the loop done by player is stopped.

The actual example is here... and it has two players.

Just add:

go player("ping", table)

And you will see (playground):

ping 1
pong 2
ping 3
pong 4
ping 5
pong 6
ping 7
pong 8
ping 9
pong 10
ping 11
pong 12

The OP adds in the comments:

I meant, why doesn't it loop more than once in player?
If you increase the sleep time to 10 it becomes more evident

Here is a playground example with main waiting 10 seconds.

player won't loop because table is an unbuffered channel: once player send the Ball back, player blocks until anyone removes that Ball from table.
And there is nobody to remove said Ball: main is sleeping 10 seconds, then removes it and exits immediately, preventing player to loop some more (because the all program has stopped)

See "do Golang channels maintain order", in order to see an illustration of unbuffered vs. buffered channels.

With table sleeping 10 seconds, but with a buffered channel (of capacity 1), here is what you would see (playground) (the player sleeps 1 second):

pong 1
pong 2
pong 3
pong 4
pong 5
pong 6
pong 7
pong 8
pong 9
pong 10
pong 11
time's up

That is: the player 1 pick itself the Ball from the table, and send it back to the table. It does not block because the buffered channel is not over-capacity.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I'm sorry I wasn't specific enough in my question. I meant, why doesn't it loop more than once in player. If you increase the sleep time to 10 it becomes more evident – user3204416 Feb 24 '18 at 03:33
  • @user3204416 I have edited the answer accordingly, and provide other playground examples to illustrate that behavior. – VonC Feb 24 '18 at 06:51
  • awesome thanks. I did not know channels held on send and receive. – user3204416 Feb 25 '18 at 04:07
  • @user3204416 in your case, an *unbuffered* channel will held on send and receive. As I illustrated, an *buffered* one would not (at least if you don't put/receive more than one Ball at a time). – VonC Feb 25 '18 at 08:51