Search code examples
gochannelselect-case

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


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


Solution

  • 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.