在Go协程中调用了defer。

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

Defer called in go routine

问题

我相信我对正常情况下的defer理解得很好,比如在这个问题中列出的情况https://stackoverflow.com/questions/24720097/golang-defer-behavior。然而,当defer在不返回的goroutine中调用时,我有点困惑发生了什么。以下是相关的代码。

  1. func start_consumer() {
  2. conn, _ := amqp.Dial("amqp://username:password@server.com")
  3. //defer conn.Close()
  4. ch, _ := conn.Channel()
  5. //defer ch.Close()
  6. q, _ := ch.QueueDeclare(
  7. "test", // name
  8. true, // durable
  9. false, // delete when unused
  10. false, // exclusive
  11. false, // no-wait
  12. nil, // arguments
  13. )
  14. _ = ch.Qos(
  15. 3, // prefetch count
  16. 0, // prefetch size
  17. false, // global
  18. )
  19. forever := make(chan bool)
  20. go func() {
  21. for {
  22. msgs, _ := ch.Consume(
  23. q.Name, // queue
  24. "", // consumer
  25. false, // ack
  26. false, // exclusive
  27. false, // no-local
  28. false, // no-wait
  29. nil, // args
  30. )
  31. for d := range msgs {
  32. log.Printf("Received a message: %s", d.Body)
  33. d.Ack(true)
  34. }
  35. time.Sleep(1 * time.Second)
  36. }
  37. }()
  38. log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
  39. <-forever
  40. }

这个函数是从以下位置调用的:

  1. go start_consumer()

这可能是我对通道工作原理的误解,但我认为forever不会返回,因为它正在等待一个值传递给它。

英文:

I believe I understand defer well in the normal use cases. Such as the one listed in this question https://stackoverflow.com/questions/24720097/golang-defer-behavior. However I am a little perplexed as to what is happening when defer is called inside a goroutine that does not return. Here is the code in question.

  1. func start_consumer() {
  2. conn, _ := amqp.Dial(&quot;amqp://username:password@server.com&quot;)
  3. //defer conn.Close()
  4. ch, _ := conn.Channel()
  5. //defer ch.Close()
  6. q, _ := ch.QueueDeclare(
  7. &quot;test&quot;, // name
  8. true, // durable
  9. false, // delete when unused
  10. false, // exclusive
  11. false, // no-wait
  12. nil, // arguments
  13. )
  14. _ = ch.Qos(
  15. 3, // prefetch count
  16. 0, // prefetch size
  17. false, // global
  18. )
  19. forever := make(chan bool)
  20. go func() {
  21. for {
  22. msgs, _ := ch.Consume(
  23. q.Name, // queue
  24. &quot;&quot;, // consumer
  25. false, // ack
  26. false, // exclusive
  27. false, // no-local
  28. false, // no-wait
  29. nil, // args
  30. )
  31. for d := range msgs {
  32. log.Printf(&quot;Received a message: %s&quot;, d.Body)
  33. d.Ack(true)
  34. }
  35. time.Sleep(1 * time.Second)
  36. }
  37. }()
  38. log.Printf(&quot; [*] Waiting for messages. To exit press CTRL+C&quot;)
  39. &lt;-forever
  40. }

This function is called from

  1. go start_consumer()

This is likely a misunderstanding by me how channels work but I though forever would not return since it's waiting for a value to be passed to it.

答案1

得分: 7

《Go Blog》中的延迟、恐慌和恢复一文在前面的问题中提到了延迟语句的工作原理。

延迟语句会将一个函数调用推入一个列表中。保存的函数调用列表会在包围它的函数返回后执行。延迟语句通常用于简化执行各种清理操作的函数。

在你的情况下,由于goroutine不会返回,保存的延迟调用列表将永远不会被执行。因此,在这种情况下,延迟语句是不必要的。

英文:

The Go Blog's Defer, Panic, and Recover post referenced in the previous question does a great job explaining how defer statements work.

> A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.

In your case since the goroutine does not return, the list of deferred calls will never be run. This makes the defer statement unnecessary in this context.

huangapple
  • 本文由 发表于 2014年12月19日 04:35:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/27555243.html
匿名

发表评论

匿名网友

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

确定