for и загрузка процессора

Собственно вопрос понятен из названия: Есть программа с несколькими гоурутинами которые работают одновременно и постоянно и которым надо посылать друг в друга уведомления. сейчас это:

botNotification := make(chan Notification, 1)

notification := Notification{Code: 1, TelegramID: user.TelegramID}
botNotification <- notification

for {
        select {
        case notification := <-botNotification:
            switch notification.Code {
            case 1:
                c.SendChatAction(notification.TelegramID, tbot.ActionTyping)
                time.Sleep(1 * time.Second)
                c.SendMessage(notification.TelegramID, translation.ManagerOpened)
            case 2:
                c.SendChatAction(notification.TelegramID, tbot.ActionTyping)
                time.Sleep(1 * time.Second)
                c.SendMessage(notification.TelegramID, translation.AdminOpened)
            default:
                c.SendChatAction(notification.TelegramID, tbot.ActionTyping)
                time.Sleep(1 * time.Second)
                c.SendMessage(notification.TelegramID, translation.NotFound)
            }
        default:
            continue
        }
    }

кроме того есть цикл for без условий для постоянной работы в фоне и возможности вводить простые команды вроде quit, statistics и подобных.

Ну и занимает это всё добро 102 процента vps'ного cpu постоянно. При запуске на рабочем компьютере (4 ядра) занимает 30%.

С этим что-то можно сделать кроме выставления таймингов (time.Sleep()) внутри каждого цикла?


Ответы (1 шт):

Автор решения: Pak Uula

У вас select не блокируется из-за default: continue

Всякий раз, когда программа проверяет наличие уведомления в канале, срабатывает select: если в канале что-то есть, то запускается обработчик, а если нет, то цикл продолжается.

Вам достаточно переписать цикл вот так:

for {
        notification = <-botNotification

        switch notification.Code {
        case 1:
            c.SendChatAction(notification.TelegramID, tbot.ActionTyping)
            time.Sleep(1 * time.Second)
            c.SendMessage(notification.TelegramID, translation.ManagerOpened)
        case 2:
            c.SendChatAction(notification.TelegramID, tbot.ActionTyping)
            time.Sleep(1 * time.Second)
            c.SendMessage(notification.TelegramID, translation.AdminOpened)
        default:
            c.SendChatAction(notification.TelegramID, tbot.ActionTyping)
            time.Sleep(1 * time.Second)
            c.SendMessage(notification.TelegramID, translation.NotFound)
        }
    }

Присваивание notification = <-botNotification блокируется до получения уведомления, поэтому цикл будет висеть в ожидании уведомления в канале и перестанет тратить CPU.

Если же вам по какой-то причине важно, чтобы цикл временами разблокировался, тогда нужно вместо default поставить таймаут:

        select {
        case notification := <-botNotification:
            switch notification.Code {
            case 1:
                c.SendChatAction(notification.TelegramID, tbot.ActionTyping)
                time.Sleep(1 * time.Second)
                c.SendMessage(notification.TelegramID, translation.ManagerOpened)
            case 2:
                c.SendChatAction(notification.TelegramID, tbot.ActionTyping)
                time.Sleep(1 * time.Second)
                c.SendMessage(notification.TelegramID, translation.AdminOpened)
            default:
                c.SendChatAction(notification.TelegramID, tbot.ActionTyping)
                time.Sleep(1 * time.Second)
                c.SendMessage(notification.TelegramID, translation.NotFound)
            }
        case <-time.After(10*time.Second):
            fmt.Println("10 seconds of inactivity")
            continue
        }
→ Ссылка