在for循环中调用defer – 有没有更好的方法来延迟从通道读取响应?

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

Calling defer in the for loop - Is there a better way to defer reading response from channels?

问题

我正在尝试在循环中调用一个返回通道的函数。然后将该通道附加到切片channelSlice上。最后,迭代通道切片并打印每个通道的响应。在执行此操作时,我的IDE显示一个警告:

可能存在资源泄漏,'defer'在'for'循环中被调用

正如你所看到的,我在第二个for循环中调用了close(channelSlice[i])。这样做是否不推荐?还有,这可能导致资源泄漏吗?有没有更好的处理关闭或通道切片的方法?

package main

import (
	"fmt"
	"math/rand"
)

func t() chan int {
	c := make(chan int)
	go func() {
		c <- rand.Intn(100)
	}()

	return c
}

func main() {
	channelSlice := make([]chan int, 0)
	for i := 0; i<100; i++ {
        // 不断进行并发调用
        // 稍后将从通道中读取响应
		channelSlice = append(channelSlice, t())
	}

	for i := 0; i<100; i++ {
		defer close(channelSlice[i]) // IDE抛出的警告
		fmt.Println(<-channelSlice[i])
	}
}
英文:

I am trying to call a function that returns a channel in a loop. The channel is then appended onto a slice channelSlice. At the end, the channel slice is iterated and the response from each channel is printed. While I do this, my IDE shows a warning:

Possible resource leak, &#39;defer&#39; is called in the &#39;for&#39; loop 

As you could see, I call close(channelSlice[i]) inside the second for loop. Is this not recommended? Also, how could this lead to a resource leak? Is there a better way to handle close or slice of channels?

package main


import (
	&quot;fmt&quot;
	&quot;math/rand&quot;
)

func t() chan int {
	c := make(chan int)
	go func() {
		c &lt;- rand.Intn(100)
	}()

	return c
}

func main() {
	channelSlice := make([]chan int, 0)
	for i := 0; i&lt;100; i++ {
        // Keep making concurrent calls
        // Will read responses from the channel later
		channelSlice = append(channelSlice, t())
	}

	for i := 0; i&lt;100; i++ {
		defer close(channelSlice[i]) // Warning thrown by IDE
		fmt.Println(&lt;-channelSlice[i])
	}
}

答案1

得分: 0

根据@mkopriva的指示,

延迟调用在包围函数退出时执行,而不是在包围非函数块退出时调用。将循环的主体封装在闭包中。

这是我所做的:

for i := 0; i<100; i++ {
    func() {
        defer close(channelSlice[i])
        fmt.Println(<-channelSlice[i])
    }()
}

正如你所看到的,我将defer语句包装在了一个IIFE(立即调用的函数表达式)中。将其作为闭包也是可以的。

这确保了通道现在将被关闭,不会出现内存泄漏。

英文:

As pointed by @mkopriva,

> Deferred calls are executed when the surrounding function exits, they are not called when the surrounding non-function block exits. Enclose the loop's body in a closure.

Here is what I did:

	for i := 0; i&lt;100; i++ {
	    func() {
			defer close(channelSlice[i])
			fmt.Println(&lt;-channelSlice[i])
		}()
	}

As you could see, I wrapped the defer statement in a IIFE (Immediately Invoked Function Expression). Making it a closure would be fine as well.

This ensures, that the channel will now be closed and there will not be a memory leak.

huangapple
  • 本文由 发表于 2023年3月10日 14:38:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75692942.html
匿名

发表评论

匿名网友

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

确定