How to make a select case non-blocking in for loop without default

1.1k Views Asked by At

I have this piece of code.

func Start() bool {
    for {
        if checkSomthingIsTrue() {
            if err := doSomthing(); err != nil {
                continue
            }
        }
        select {
        case <-ctx.Done():
            return true
        }
    }
}

How to make the above function non blocking without using default: case. reason to not use default case is because its eating up 100% CPU always.

Answer: I have used time.Ticker to throttle Thanks

1

There are 1 best solutions below

3
Dietrich Epp On BEST ANSWER

There is a fundamental misunderstanding here. A thread can do only two things:

  • A thread can block, waiting for something.

  • A thread can run, using CPU.

If a thread never blocks, then it uses 100% of the available CPU. You cannot make non-blocking code use less than 100% of the available CPU.

You have three options:

  1. Use non-blocking code, and accept the 100% CPU usage.

  2. Redesign checkSomthingIsTrue() so it uses a channel, and can be put inside the select block.

    for {
        select {
        case <-ctx.Done():
            return true
        case <-whenSomethingIsTrue():
            if err := doSomthing(); err != nil {
                continue
            }
        }
    }
    
  3. Use a timeout to throttle the loop, for example:

    // Poll every 100ms.
    const pollInterval = 100 * time.Millisecond
    for {
        select {
        case <-ctx.Done():
            return true
        case <-time.After(pollInterval):
            if checkSomthingIsTrue() {
                if err := doSomthing(); err != nil {
                    continue
                }
            }
        }
    }
    

Also note that continue makes no sense, but that is a different issue.