为什么Go协程在Gin的处理程序中一直工作到结束

huangapple go评论78阅读模式
英文:

Why go routine works till end from a Gin's handler

问题

我知道如果 goroutine B 是从某个 goroutine A 启动的,而且如果 goroutine A 结束了,无论 goroutine B 走了多远,它最终都会被强制结束。

func main() {
	go simulateGinAPI()
	fmt.Println("finish...")
}

func simulateGinAPI() {
	fmt.Println("ginAPI....")
	go backgroundProcess()
}

func backgroundProcess() {
	fmt.Println("calculating...")
	fmt.Println(calculate(45))
}

func calculate(x int) int {
	if x < 2 {
		return x
	}
	return calculate(x-1) + calculate(x-2)
}

输出结果为:

finish...

正如输出日志所示,斐波那契和的结果没有被记录下来,只有 "finish" 被记录下来。


然而,如下所示的代码,如果我们从 Gin 的处理函数中启动 goroutine,即使响应已经发送,用于计算斐波那契和结果的 goroutine 仍然会一直运行到结束。

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		go backgroundProcess()
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

func simulateGinAPI() {
	fmt.Println("ginAPI....")
	go backgroundProcess()
}

func backgroundProcess() {
	fmt.Println("calculating...")
	fmt.Println(calculate(45))
}

func calculate(x int) int {
	if x < 2 {
		return x
	}
	return calculate(x-1) + calculate(x-2)
}

输出结果为:

[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
calculating...
[GIN] 2021/12/20 - 11:31:46 | 200 | 56.425µs | ::1 | GET      "/ping"
1134903170 <- 斐波那契和的结果。

问题:

  1. 为什么从 Gin 的处理函数中启动的 goroutine 在响应发送后没有被强制结束?
  2. 响应发送后,处理函数的 goroutine 不应该被结束吗?
  3. 从处理函数启动的 goroutine 不应该随着处理函数的结束而被强制结束吗?
英文:

I know that if the goroutine B is started from a certain goroutine A, and if the goroutine A ends, no matter how far does goroutine B steps, it will be ended up forcefully.

func main()  {
	go simulateGinAPI()
	fmt.Println(&quot;finish...&quot;)
}

func simulateGinAPI() {
	fmt.Println(&quot;ginAPI....&quot;)
	go backgroundProcess()
}


func backgroundProcess() {
	fmt.Println(&quot;calculating...&quot;)
	fmt.Println(calculate(45))
}

func calculate(x int) int {
	if x &lt; 2 {
		return x
	}
	return calculate(x-1) + calculate(x-2)
}

output

finish...

As the output log shows. Result of Fibonacci sum will not be logged out, instead, only "finish" was logged out.


However, as the code below shows, if we start gorouting from a Gin's handle, even the response was sent, goroutine for calculating the result of Fibonacci sum will still be run to the end.


func main() {
	r := gin.Default()
	r.GET(&quot;/ping&quot;, func(c *gin.Context) {
		go backgroundProcess()
		c.JSON(200, gin.H{
			&quot;message&quot;: &quot;pong&quot;,
		})
	})
	r.Run() // listen and serve on 0.0.0.0:8080 (for windows &quot;localhost:8080&quot;)
}

func simulateGinAPI() {
	fmt.Println(&quot;ginAPI....&quot;)
	go backgroundProcess()
}


func backgroundProcess() {
	fmt.Println(&quot;calculating...&quot;)
	fmt.Println(calculate(45))
}

func calculate(x int) int {
	if x &lt; 2 {
		return x
	}
	return calculate(x-1) + calculate(x-2)
}

为什么Go协程在Gin的处理程序中一直工作到结束

output

[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
calculating...
[GIN] 2021/12/20 - 11:31:46 | 200 |      56.425&#181;s |             ::1 | GET      &quot;/ping&quot;
1134903170 &lt;- result of Fibonacci&#39;s sum.

Question:

  1. Why the goroutine started from handle of gin was not end up
    forcefully after the gin's handle send response?
  2. Should not the goroutine of the handle be ended up after the
    response was sent?
  3. Should not the goroutine started from handle be ended up forcefully
    with the end of the goroutine on the handle?

答案1

得分: 6

我知道,如果 goroutine B 是从某个 goroutine A 启动的,而且如果 goroutine A 结束了,无论 goroutine B 走了多远,它都会被强制结束。

这是不正确的。如果 main 函数退出,所有的 goroutine 也会退出。

但是如果 main 函数继续运行,尽管 goroutine 的调用函数退出了,该 goroutine 仍会继续执行。

你的示例代码在计算 Fibonacci 和之前就退出了。但是你的服务器代码继续运行。这就是代码的行为。

如果你稍微修改一下示例代码,你会发现程序也会计算出 Fibonacci 和。

这是示例代码:https://goplay.tools/snippet/dMCyUqweyu8

英文:

> I know that if the goroutine B is started from a certain goroutine A, and if the goroutine A ends, no matter how far does goroutine B steps, it will be ended up forcefully.

It's not correct. If the main function exits, all the goroutines will be exited too.

But if the main function continues running, although the goroutine caller function exits, that goroutine will continue its course.

This happened in your example too.

Your example code exits before it could calculate the Fibonacci sum. But your server code continues running. That's why this behavior from the code.

If you altered your example code a bit, you could see that your program also calculates the Fibonacci sum.

Here's the example: https://goplay.tools/snippet/dMCyUqweyu8

huangapple
  • 本文由 发表于 2021年12月20日 10:57:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/70416983.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定