Generally, a business rarely does not use goroutine because many methods require waiting, for exampleThis is waiting, and will not return unless the Server or Listener is turned off. Unless it is an API server, it is necessary to initiate other services from goroutine, and for the API server,
The handling function generally also needs to be goroutines. How to manage these goroutines is provided in GOLANG1.7
。
Let’s first look at a simple one. If you start two goroutines, one is HTTP, and there is also a signal processing that receives the exit signal to clean up:
wg := {} defer () (1) go func() { defer () ss := make(, 0) (ss, , ) for s := ss { ("Got signal", s) break } }() (1) go func() { defer () svr := &{ Addr:":8080", Handler:nil, } (()) }
It is clear that two goroutines were set up, and then WaitGroup was used to wait for them to exit. If there is no interaction between them and does not affect each other, it is really simple. Unfortunately, this is not possible, because after the signal's goroutine receives the exit signal, the server should be notified to exit. What is more violent is to call it directly()
, but what if some requests still need to be cancelled? It's best to use Context:
wg := {} defer () ctx,cancel := (()) (1) go func() { defer () ss := make(chan , 0) (ss, , ) select { case <- (): return case s := <- ss: ("Got signal", s) cancel() // Cancel the request and notify all goroutines of ctx return } }() (1) go func() { defer () defer cancel() svr := &{ Addr:":8080", Handler:nil, } go func(){ select { case <- (): () } } (()) }
This method can be used when a new goroutine is opened, for example, adding a new goroutine, which reads and writes UDPConn:
(1) go func() { defer () defer cancel() var conn * if conn,err = ("udp", "127.0.0.1:1935"); err != nil { ("Dial UDP server failed, err is", err) return } (UDPRead(ctx, conn)) }() UDPRead = func(ctx , conn *) (err error) { wg := {} defer () ctx, cancel := (ctx) (1) go func() { defer () defer cancel() for { b := make([]byte, ) size, _, err := (b) // Process UDP packet b[:size] } }() select { case <-(): () } return }
If you only use HTTP Server, you can write this:
func run(ctx ) { server := &{Addr: addr, Handler: nil} go func() { select { case <-(): () } }() ("/api", func(w , r *) { }) (()) }
If you need to provide an API to get the server out, you can write this:
func run(ctx ) { server := &{Addr: addr, Handler: nil} ctx, cancel := (ctx) ("/quit", func(w , r *) { cancel() // Use local ctx and cancel }) go func() { select { case <-(): () } }() (()) }
Using local ctx and cancel can avoid the ctx passed in by cancel, and only affect the current ctx.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.