Пойти на главную главную роль в горуте?

Есть ли какой-либо API, чтобы позволить main goroutine спать навсегда?

Другими словами, я хочу, чтобы мой проект выполнялся всегда, за исключением случаев, когда я его останавливаю.

Ответ 1

"Спящий"

Вы можете использовать многочисленные конструкции, которые блокируются навсегда, не "съедая" ваш процессор.

Например, a select без каких-либо case (и no default):

select{}

Или получение с канала, где никто ничего не отправляет:

<-make(chan int)

Или получение из канала nil также блокируется навсегда:

<-(chan int)(nil)

Или отправка по каналу nil также блокируется навсегда:

(chan int)(nil) <- 0

Или заблокировать уже заблокированный sync.Mutex:

mux := sync.Mutex{}
mux.Lock()
mux.Lock()

Выход

Если вы хотите предоставить способ выхода, простой канал может это сделать. Предоставьте канал quit и получите от него. Когда вы хотите выйти, закройте канал quit, поскольку "операция приема на закрытом канале всегда может начинаться немедленно, давая тип элемента нулевое значение после любого ранее отправленного значения были получены".

var quit = make(chan struct{})

func main() {
    // Startup code...

    // Then blocking (waiting for quit signal):
    <-quit
}

// And in another goroutine if you want to quit:
close(quit)

Обратите внимание, что выдача close(quit) может прекратить ваше приложение в любое время. Цитата из Spec: Выполнение программы:

Выполнение программы начинается с инициализации основного пакета и последующего вызова функции main. Когда возвращается эта функция, программа завершает работу. Он не ждет завершения других (не main) goroutines.

Когда выполняется close(quit), может действовать последний оператор нашей функции main(), что означает, что gotoutine main может вернуться, поэтому программа завершает работу.

Ответ 2

В зависимости от вариантов использования вы выбираете, какого сна вы хотите.

@icza предоставляет хорошее и простое решение для буквального спящего навсегда, но я хочу дать вам еще несколько сладостей, если вы хотите, чтобы ваша система могла законно прекратиться.

Вы можете сделать что-то вроде этого:

func mainloop() {
    exitSignal := make(chan os.Signal)
    signal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM)
    <-exitSignal

    systemTeardown()
}

И в основном:

func main() {
    systemStart()
    mainloop()
}

Таким образом, вы можете не только просить ваш основной спать вечно, но вы можете сделать некоторые изящные выключения после того, как ваш код получит сигнал INT или TERM от ОС, например ctrl+C или kill.