dongqiao8421 2013-01-31 19:13
浏览 27
已采纳

当没有通道可供读取时,怎么办?

Let's take this example from the GoTour, as it illustrates my problem with processing SDL events only when there are events.

package main

import (
"fmt"
"time"
)

func main() {
tick := time.Tick(1e8)
boom := time.After(5e8)
for {
    select {
    case <-tick:
        fmt.Println("tick.")
    case <-boom:
        fmt.Println("BOOM!")
        return
    default:
        fmt.Println("    .")
        time.Sleep(5e7)
    }
}
}

This works. But what if I don't want to print or sleep in the default case, but just want to keep looping? I tried this:

    case <-boom:
        fmt.Println("BOOM!")
        return
    default: // Nothing here.
    }
}
}

but it blocks.

I have seen here and there a sentence about goroutines scheduling, but I didn't understand them. So I guess I have two questions:

1) Why does it block?

2) How do I make it do nothing without blocking?

  • 写回答

1条回答 默认 最新

  • dpik71879 2013-01-31 20:29
    关注

    Your Original Example produces this

        .
        .
    tick.
        .
        .
    tick.
        .
        .
    tick.
        .
        .
    tick.
        .
        .
    tick.
    BOOM!
    

    Wheraeas Your Second Example produces this

    [process took too long]
    

    The difference is what you did in the default case. A default case is always ready to run so a select with a default statement in it never blocks. The second example runs round the loop continuously choosing one of the branches (case or default) that is ready to run. You are now wondering why the the timer never fires. That is because go routines are not pre-emptively scheduled. So because the loop below never does any IO, the time ticks never fire.

    for {
        select {
            // whatever
            default:
        }
    }
    

    There are a number of ways of fixing this. Firstly you can put some IO in like you did in your first example. Or you could put a runtime.Gosched() in. Or you could allow the go runtime to use more than one thread with runtime.GOMAXPROCS(2) all of which will work.

    The best way IMHO is to leave out the default statement entirely like this. A select without a default statement will block until one of the case statements is ready. If you want to do some background processing (that you were doing in the default statement) then start a goroutine - that is the go way!

    In fact I've seen so many problems with default in select statements that I'd be tempted to say to never use them.

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

报告相同问题?

悬赏问题

  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 unity第一人称射击小游戏,有demo,在原脚本的基础上进行修改以达到要求
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)