请教下golang goroutine泄露问题?

breadHood · · 3278 次点击
大佬们考虑非常细致, 感谢!
#9
更多评论
简单改一下,不知道理解的对不对哈,始终只监听最新的文件,所以 `eventName` 每次替换 ```go go func() { var ctx,cancel = context.WithCancel(context.Background()) var eventName string for { select { case event := <-watcher.Events: // 如果是同一文件,跳过 if eventName == event.Name { continue } isMatch := re.MatchString(event.Name) if isMatch { // 更换文件了,cancel 上次的 go DealLog cancel() // 文件名更新 eventName = event.Name if event.Op&fsnotify.Create == fsnotify.Create { // 监控创建文件动作 fmt.Println(event.Name) // 重新赋值 ctx, cancel = context.WithCancel(context.Background()) go DealLog(ctx, event.Name) } if event.Op&fsnotify.Write == fsnotify.Write { // 监控写入文件动作 fmt.Println(event.Name) ctx, cancel = context.WithCancel(context.Background()) go DealLog(ctx, event.Name) } } case err := <-watcher.Errors: log.Println(err) } time.Sleep(time.Second * 1) } }() ``` ```go // 读取每行数据,最后写入到AllAddrLoglist中. for { select { case line, ok = <-tails.Lines: .... case <-ctx.Done(): return } } ```
#1
buguang01
https://github.com/buguang01
从楼主的问题中我理解,你当前只希望监听一个文件,只是这个文件随时可能会更换新的;同时新的内容可能是写在新文件中,也可能是旧文件的修改; 但是我看到楼主使用的是tail进行文件的读取,其实存在一个问题,就是对方文件都写完了,你再tail其实会丢失一些数据; 一般第三方的日志系统都是写同一个文件,然后文件写到一定大小的时候,修改文件名字,然后再创建一个原来的文件; 这样监听文件的系统就不用频繁换文件了; --- 但如果只是就楼主的问题进行探讨的话,我先说一下,楼主当前程序的几个问题: 1. DealLog函数的ch 是没有意义的。因为他是局部变量不会起到锁的作用; 2. 假设你理解的是对的,这样使用tail不会丢数据,那也不应该是每收到一个event就开一个协程,而是在收到event的时候,直接把那个文件的数据读到文件结束,然后保存到你的map中,然后继续等一次的event过来; 因为watcher底层开着一个协程监听你的目录中所有文件的变化;每次收到变化的时候,他就会发一个event给你;你直接处理就好了。 总结:如果是这样修改,你不会有开多个协程,也就不存在楼主关于协程泄漏的问题了; --- 再假设楼主的环境是可能同时多个文件被写入,希望可以并发的获取数据;方案如下: 1. 首先程序启动的时候,应该对目录下所有的文件,启动协程进行tail; 2. 然后watcher目录是否有新的文件生成,如果有,就为此启动协程进行tail; 总结:如果是这样修改,也就是需求需要一个文件一个协程。你的额外的协程数就是你的目录下的文件数,且还都不能关闭;
#2