Golang Go语言中 goroutine 的泄露应该怎么处理
Golang Go语言中 goroutine 的泄露应该怎么处理
package main
import (
“bufio”
“fmt”
“github.com/sparrc/go-ping”
“log”
“os”
“time”
)
type PingRestult struct {
ip string
time time.Duration
}
func MultiPing(urls []string, ch chan PingRestult) {
for {
for _, url := range urls {
go PingIp(url, ch)
}
time.Sleep(1 * time.Second)
}
}
func GetResult(ch chan PingRestult) {
for {
fmt.Println(<-ch)
}
}
func PingIp(ip string, ch chan PingRestult) {
pinger, err := ping.NewPinger(ip)
pinger.SetPrivileged(true)
if err != nil {
panic(err)
}
pinger.Count = 1
pinger.Timeout = time.Second * 1
pinger.Run()
// blocks until finished
stats := pinger.Statistics()
result := PingRestult{ip, stats.AvgRtt}
ch <- result
}
func main() {
file, err := os.Open(“file.txt”)
if err != nil {
log.Fatal(err)
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
ch := make(chan PingRestult, len(lines))
defer close(ch)
go GetResult(ch)
MultiPing(lines, ch)
select {}
}
在 file.txt 有 ip 列表,取出来,放在一个死循环中得到 ping 的结果。
但是 MultiPing 中好像会有内存泄露,应该是回收的地方做的不对。
问问大佬们这种咋处理。感谢。
更多关于Golang Go语言中 goroutine 的泄露应该怎么处理的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这不叫泄露,你代码本来就不限制并发量。
更多关于Golang Go语言中 goroutine 的泄露应该怎么处理的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
刚刚看了你用的库的文档,例子里有 Stop 函数,ping 结束你调用下 Stop 函数看下呢。
生产者消费者模型找个教程看下吧,你没有限制消费者数量。
请问具体 goroutine 泄露的表现是什么呢?在 pprof 中发现 无论 ping 任务是否结束 goroutine 都保持在一个很高的数吗?
还是在执行 ping 的任务时很多,执行完数量就回落了呢?
同样,如果在 pprof 的 goroutine 中会打印函数调用栈信息,可以发现究竟都在哪发生了阻塞,可以快速定位出造成阻塞的 goroutine 代码。
看了下 go-ping 这个库,猜测可能是并发量大导致了死锁,有 issue: https://github.com/sparrc/go-ping/issues/77,可以尝试按照 issue 描述的方式增加 channel 容量,看看能否解决.
#5 我主要是不确定,MultiPing 方法里面 for 死循环中,里面开 goroutine,这些 goroutine 会被回收吗,还是会泄露。我试试逻辑里面不去调用 ping,就直接把传入 PingIp 的值放入 ch 中,看看这种情况下是否会泄露。
#6 试过增加容量,还是有问题。应该不是。问题应该是 reus 所说的,要用一个 pool 池。
就问你 发请求的函数没有 ctx 参数 心里虚不虚
没细看, 猜测要在 PingIP 函数加超时 context 吧, 同意楼上
MultiPing 按照我的理解,是主 Goroutine 执行的,本身如果是死循环的话,主程序 不会终止。
此外就是楼上说到的,如果 ping 那边有阻塞的话,也会使得调用其的 goroutine 阻塞了。建议可以看看 ping 那边的超时参数
#9
#10 超时那边应该是 pinger.Timeout = time.Second * 1 这个吧,我设置了。
报告各位大佬,首先我的第一个实现版本是有问题。 现在我按照 http://jmoiron.net/blog/limiting-concurrency-in-go/ 这个里面的用法,以及用了 workerpool 的用法,我发现是不是这个 go-ping 库有问题啊,我把 PingIp 这个函数变为直接打印出来,就啥错误都没了。https://pastebin.com/89KknAMV
好吧 查出来了,我自己写的有问题。
具体是什么问题呢? 我看了下 go-ping 这个库, 似乎直接设置下 pinger.Timeout 就行
问题解决了要反馈下楼上的热心老哥
我这个版本,写的不太好。MultiPing 这边 for 循环里面写了个 go PingIp,相当于无限消费者。所以内存爆炸了。
新写了一个版本,生产者读取 file.txt 送到一个 chan 里面去,然后 main 函数里面开 goroutine 作为消费者,消费 chan 里面的 ip 就行了。goroutine 的个数可以自己控制,也可以按照二楼老哥的方案,弄个池子。
在Go语言中,处理goroutine泄露是一个重要而复杂的任务。goroutine泄露通常发生在goroutine被错误地启动但没有被适当地终止或回收,导致系统资源(如内存和文件描述符)被不必要地占用,最终可能导致程序崩溃或性能下降。
要处理goroutine泄露,可以采取以下策略:
-
确保goroutine的终止:为每个goroutine设置一个明确的退出条件,并确保在适当的时候退出。这通常涉及使用通道(channel)或其他同步机制来通知goroutine何时停止工作。
-
使用context包:在Go 1.7及更高版本中,可以使用
context
包来管理goroutine的生命周期。通过传递一个context.Context
对象给goroutine,可以在需要时取消它。 -
监控和分析:使用Go的内置工具(如pprof)或第三方工具来监控和分析goroutine的行为。这些工具可以帮助你识别哪些goroutine没有被正确终止。
-
代码审查和测试:在代码审查和测试阶段,特别注意那些启动goroutine的部分,确保它们有适当的退出和清理机制。
-
定期重构和优化:随着程序的发展,定期重构和优化代码,确保goroutine的使用是高效且安全的。
通过实施这些策略,你可以有效地减少或消除Go程序中的goroutine泄露问题。