duanguo7021 2018-02-23 04:42
浏览 27
已采纳

为什么此代码停顿?

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条回答 默认 最新

  • duanlie3187 2018-02-23 05:47
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置