Цикл выбора горутины с тикером приводит к загрузке ЦП на 100%

У меня есть эта петля, которая пытается повторно опросить другой сервер. Для этого я использовал тикер, однако программа постоянно показывает 100% загрузку ЦП.

Этот тикер работает внутри горутины. и HTTP-сервер работает внутри другой горутины.


func() Monitor() {

  abort := make(chan bool)

  log.Info("Monitor started.")

  // start the monitor goroutine
  go func() {
      defer log.Info("Stopped monitor")
        
      ticker := time.NewTicker(time.Duration(35.0) * time.Second)
      defer ticker.Stop()
        
      log.Info("Monitor started! \n")
      for {
        select {
        case t := <-ticker.C:
            log.Infof("Subscribe to service at time %v\n", t)
            if err := selfConn.SubscribeToService(); err != nil {
                log.Errorf("Failed to subscribe to primary connector: %v", err)
            } 
        case <-abort:
            log.Info("Finished routine!")
            return
        default:
            continue
        }
        }
    }() 
  
    go func() {
        time.Sleep(10 * time.Minute)
        abort <- true
    }()
}

Однако, когда запускаются циклы мониторинга и каждый раз, когда отправляется сигнал на канал тикера, ЦП постоянно показывает 100%.

Что я упустил при использовании тикера в горутине, чтобы он не потреблял 100% ресурсов ЦП?


person Abigail Nguyen    schedule 14.09.2020    source источник
comment
Не могли бы вы оставить комментарий о том, почему вы проголосовали против вопроса? Это мой первый вопрос, заданный в сообществе, и я совсем недавно изучаю параллелизм Go. Мне было бы полезно опубликовать свой следующий вопрос на сайте.   -  person Abigail Nguyen    schedule 18.09.2020


Ответы (1)


У вас есть select с ветвью default внутри цикла. Если ни один из других case не готов к продолжению, ветвь default выполняется немедленно, поэтому ваша следующая итерация начинается немедленно без ожидания. Это занятая петля.

Кроме того, нет необходимости завершать другую горутину, вы можете использовать для этого таймер в той же горутине.

Например:

func monitor() {
    log.Info("Monitor started.")

    ticker := time.NewTicker(35 * time.Second)
    defer ticker.Stop()

    timeoutCh := time.After(10 * time.Minute)
    for {
        select {
        case t := <-ticker.C:
            log.Infof("Subscribe to service at time %v\n", t)
            if err := selfConn.SubscribeToService(); err != nil {
                log.Errorf("Failed to subscribe to primary connector: %v", err)
            }
        case <-timeoutCh:
            log.Info("Finished routine!")
            return
        }
    }
}
person icza    schedule 14.09.2020
comment
Большое спасибо! Да, я удалил дефолт, и он ведет себя намного лучше. Вы правы :) Я просто добавил таймер завершения например, он должен быть 10 минут, а интервал опроса 35 секунд. Ваш пример - это то, что я ищу :). Благодарю вас! - person Abigail Nguyen; 14.09.2020