在Go协程中调用了defer。

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

Defer called in go routine

问题

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

func start_consumer() {
    conn, _ := amqp.Dial("amqp://username:password@server.com")
    //defer conn.Close()

    ch, _ := conn.Channel()
    //defer ch.Close()

    q, _ := ch.QueueDeclare(
        "test", // name
        true,   // durable
        false,  // delete when unused
        false,  // exclusive
        false,  // no-wait
        nil,    // arguments
    )

    _ = ch.Qos(
        3,     // prefetch count
        0,     // prefetch size
        false, // global
    )

    forever := make(chan bool)

    go func() {
        for {
            msgs, _ := ch.Consume(
                q.Name, // queue
                "",     // consumer
                false,  // ack
                false,  // exclusive
                false,  // no-local
                false,  // no-wait
                nil,    // args
            )

            for d := range msgs {
                log.Printf("Received a message: %s", d.Body)
                d.Ack(true)
            }

            time.Sleep(1 * time.Second)
        }
    }()

    log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
    <-forever
}

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

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.

func start_consumer() {
	conn, _ := amqp.Dial(&quot;amqp://username:password@server.com&quot;)
	//defer conn.Close()

	ch, _ := conn.Channel()
	//defer ch.Close()

	q, _ := ch.QueueDeclare(
		&quot;test&quot;, // name
		true,   // durable
		false,  // delete when unused
		false,  // exclusive
		false,  // no-wait
		nil,    // arguments
	)

	_ = ch.Qos(
		3,     // prefetch count
		0,     // prefetch size
		false, // global
	)

	forever := make(chan bool)

	go func() {
		for {
			msgs, _ := ch.Consume(
				q.Name, // queue
				&quot;&quot;,     // consumer
				false,  // ack
				false,  // exclusive
				false,  // no-local
				false,  // no-wait
				nil,    // args
			)

			for d := range msgs {
				log.Printf(&quot;Received a message: %s&quot;, d.Body)
				d.Ack(true)
			}

			time.Sleep(1 * time.Second)
		}
	}()

	log.Printf(&quot; [*] Waiting for messages. To exit press CTRL+C&quot;)
	&lt;-forever
}

This function is called from

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:

确定