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

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

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

问题

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

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

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

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. )
  6. func t() chan int {
  7. c := make(chan int)
  8. go func() {
  9. c <- rand.Intn(100)
  10. }()
  11. return c
  12. }
  13. func main() {
  14. channelSlice := make([]chan int, 0)
  15. for i := 0; i<100; i++ {
  16. // 不断进行并发调用
  17. // 稍后将从通道中读取响应
  18. channelSlice = append(channelSlice, t())
  19. }
  20. for i := 0; i<100; i++ {
  21. defer close(channelSlice[i]) // IDE抛出的警告
  22. fmt.Println(<-channelSlice[i])
  23. }
  24. }
英文:

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:

  1. 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?

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;math/rand&quot;
  5. )
  6. func t() chan int {
  7. c := make(chan int)
  8. go func() {
  9. c &lt;- rand.Intn(100)
  10. }()
  11. return c
  12. }
  13. func main() {
  14. channelSlice := make([]chan int, 0)
  15. for i := 0; i&lt;100; i++ {
  16. // Keep making concurrent calls
  17. // Will read responses from the channel later
  18. channelSlice = append(channelSlice, t())
  19. }
  20. for i := 0; i&lt;100; i++ {
  21. defer close(channelSlice[i]) // Warning thrown by IDE
  22. fmt.Println(&lt;-channelSlice[i])
  23. }
  24. }

答案1

得分: 0

根据@mkopriva的指示,

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

这是我所做的:

  1. for i := 0; i<100; i++ {
  2. func() {
  3. defer close(channelSlice[i])
  4. fmt.Println(<-channelSlice[i])
  5. }()
  6. }

正如你所看到的,我将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:

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

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:

确定