How to prevent a Go program from exiting?

Original link: https://colobu.com/2023/05/22/how-to-block-the-go-app-exit/

Let me share with you a collection of methods to prevent Go programs from exiting, and there are still some methods that open the mind. Do you have any other methods to prevent the Go program from exiting? Welcome to leave a message in the message area.

For a program like the following, the program exits as soon as it runs. The reason is that the execution of the main goroutine is finished. Although the sub-goroutine exists, it fails to prevent the execution of the main goroutine:


1
2
3
4
5
6
7

package main
import “net/http”
func main() {
go http.ListenAndServe( “:8080” , nil )
}

I’ve compiled 11 ways to see if you can figure it out.

Method 1: Infinite loop

This method is a silly method that consumes one CPU core idling.


1
2
3
4
5
6
7
8
9
10

package main
import “net/http”
func main() {
go http.ListenAndServe( “:8080” , nil )
for {
}
}

Method 2: select{}

This is a technique I often use when writing examples. I like to use the select statement without a case. The number of words is small enough.


1
2
3
4
5
6
7
8
9

package main
import “net/http”
func main() {
go http.ListenAndServe( “:8080” , nil )
select {}
}

Method 3: Read or put data from a channel without buffering

Both methods will be blocked.


1
2
3
4
5
6
7
8
9
10
11

package main
import “net/http”
func main() {
go http.ListenAndServe( “:8080” , nil )
c := make ( chan struct {})
// <-c
c <- struct {}{}
}

Method 4: Read or put data from a nil channel

Both methods will be blocked.


1
2
3
4
5
6
7
8
9
10
11
12

package main
import “net/http”
func main() {
go http.ListenAndServe( “:8080” , nil )
var c chan struct {}
// <- c
c <- struct {}{}
}

Method 5: Mutex lock

Read-write locks are similar.


1
2
3
4
5
6
7
8
9
10
11
12
13
14

package main
import (
“net/http”
“sync”
)
func main() {
go http.ListenAndServe( “:8080” , nil )
var m sync.Mutex
m. Lock()
m. Lock()
}

Method 6: WaitGroup

Maybe you have already mastered the routine, and many synchronization primitives are available, such as Cond and semaphore, so we will not repeat the introduction.


1
2
3
4
5
6
7
8
9
10
11
12
13
14

package main
import (
“net/http”
“sync”
)
func main() {
go http.ListenAndServe( “:8080” , nil )
var wg sync.WaitGroup
wg. Add (1 )
wg. Wait()
}

Method 7: Blocking I/O

The easiest way is to use os.Stdin , but you can also use files, sockets, etc., as long as you block I/O.


1
2
3
4
5
6
7
8
9
10
11
12

package main
import (
“net/http”
“os”
)
func main() {
go http.ListenAndServe( “:8080” , nil )
os.Stdin.Read( make ([] byte , 1 ))
}

Method 8: Use signal.Notify

This is a trick I often use in products, capturing os.Signal to achieve graceful exit.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

package main
import (
“net/http”
“os”
“os/signal”
)
func main() {
go http.ListenAndServe( “:8080” , nil )
c := make ( chan os. Signal, 1 )
signal. Notify(c, os. Interrupt)
<-c
}

Method 9: Using a variant of signal.Notify

Using Context, the context can be passed to the child goroutine, and the Context is also suitable for use with select.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

package main
import (
“context”
“net/http”
“os”
“os/signal”
)
func main() {
go http.ListenAndServe( “:8080” , nil )
ctx, stop := signal. NotifyContext(context. Background(), os. Interrupt)
defer stop()
<- ctx. Done()
}

Method ten: fmt.Scanln()

A more concise way of blocking I/O.


1
2
3
4
5
6
7
8
9
10
11
12

package main
import (
“fmt”
“net/http”
)
func main() {
go http.ListenAndServe( “:8080” , nil )
fmt. Scanln()
}

Method Eleven: runtime.Goexit()

The main program exits but the function does not return until the child goroutine completes.


1
2
3
4
5
6
7
8
9
10
11
12

package main
import (
“net/http”
“runtime”
)
func main() {
go http.ListenAndServe( “:8080” , nil )
runtime. Go exit()
}

What other methods do you know?

This article is transferred from: https://colobu.com/2023/05/22/how-to-block-the-go-app-exit/
This site is only for collection, and the copyright belongs to the original author.