为了账号安全,请及时绑定邮箱和手机立即绑定

从文件中解析数据时大小不同的地图的地图

从文件中解析数据时大小不同的地图的地图

Go
翻阅古今 2023-07-10 10:44:27
我正在为 Nagios 构建一个 API 。我开始重新创建读取 status.dat 文件并将数据存储在多个对象中的代码,然后使用这些对象创建在 core.py 文件中找到的主机、服务、信息字典。下面是我的 Go 版本的 python 代码,它似乎按预期工作。它仍处于早期阶段,因此我对任何编码不当做法表示歉意。
查看完整描述

3 回答

?
万千封印

TA贡献1891条经验 获得超3个赞

var mu = &sync.RWMutex{}


func openStatusFile() *os.File {

    file, err := os.Open("/usr/local/nagios/var/status.dat")

    if err != nil {

    }

    return file

}


func nextStanza() <-chan map[string]string {


    myChannel := make(chan map[string]string)


    scanner := bufio.NewScanner(openStatusFile())


    current := make(map[string]string)


    go func() {

        for scanner.Scan() {

            mainline := scanner.Text()

            line := strings.TrimSpace(mainline)

            if strings.HasSuffix(line, "{") {

                if len(current) != 0 {

                    myChannel <- current

                }

                result := strings.SplitN(line, " ", 2)

                mu.Lock()

                current["type"] = result[0]

                mu.Unlock()

            } else if strings.Contains(line, "=") {

                result := strings.SplitN(line, "=", 2)

                key := result[0]

                val := result[1]

                mu.Lock()

                current[key] = val

                mu.Unlock()

            }

        }

        close(myChannel)

    }()

    return myChannel

}

在主函数中,我创建了嵌套映射以暂时仅保存主机数据,并且完成后没有任何抱怨。我遇到的问题是,当我检查此映射的长度时,我期望看到 104 个主机,但每次运行此测试文件时都会得到不同的结果。


func main() {


    hoststatus := nextStanza()


    hosts := make(map[string]map[string]string)

    // services := make(map[string]map[string]map[string]string)

    var host string

    // var service string


    for obj := range hoststatus {

        var hostPlaceHolder string

        var typePlaceHolder string


        mu.Lock()

        hostPlaceHolder = obj["host_name"]

        mu.Unlock()


        if hostPlaceHolder != "" {

            host = hostPlaceHolder

        }


        mu.Lock()

        typePlaceHolder = obj["type"]

        mu.Unlock()


        if typePlaceHolder == "hoststatus" {

            mu.Lock()

            hosts[host] = obj

            mu.Unlock()

        }

    }

    fmt.Println(len(hosts))

}

第一次运行:


$ go run -race mytest.go

93

第二次运行:


$ go run -race mytest.go

95

第三次运行:


$ go run -race mytest.go

63

你明白了。


我觉得问题与地图有关,因为如果我只是打印主机而不将它们放入地图中,我会看到我期望的所有主机。每次运行时地图尺寸不同的原因是什么?


查看完整回答
反对 回复 2023-07-10
?
慕无忌1623718

TA贡献1744条经验 获得超4个赞

我能够通过在将地图current发送到频道后清空地图来解决我的问题。


myChannel <- current

current = make(map[string]string)

然后在循环main()后的函数中for obj := range hoststatus,我将这些数据放入一个单独的映射中,然后进行处理。


hostStatusMap := make(map[string]string)

    for k, v := range obj {

        hostStatusMap[k] = v

    }

我还能够删除分散在代码中的锁,现在它在每次运行时返回正确的主机长度。


查看完整回答
反对 回复 2023-07-10
?
holdtom

TA贡献1805条经验 获得超10个赞

您的代码具有以下竞争条件


func nextStanza() <-chan map[string]string {


    myChannel := make(chan map[string]string)


    scanner := bufio.NewScanner(openStatusFile())


    current := make(map[string]string)


    go func() {

        for scanner.Scan() {

            mainline := scanner.Text()

            line := strings.TrimSpace(mainline)

            if strings.HasSuffix(line, "{") {

                if len(current) != 0 {

                    myChannel <- current

                }

                result := strings.SplitN(line, " ", 2)

                mu.Lock()

                current["type"] = result[0]

                mu.Unlock()

            } else if strings.Contains(line, "=") {

                result := strings.SplitN(line, "=", 2)

                key := result[0]

                val := result[1]

                mu.Lock()

                current[key] = val

                mu.Unlock()

            }

        }

        close(myChannel)

    }()

    return myChannel

}

当您在匿名函数上启动 goroutine 时,您并没有为其创建 WaitGroup。这意味着该函数nextStanza()将启动 goroutine,而return无需等待匿名 goroutine 终止——从而在父函数关闭时结束 goroutine。


我建议使用等待组,这样可以保证匿名函数终止。


一个简单的例子说明了正在发生的事情:


具有竞争条件


import (

    "fmt"

    "time"

    // "sync"

    )


func main() {

    go func() {

        time.Sleep(3 * time.Second)

        fmt.Println("hai")

    }()

    return

}

没有竞争条件


import (

    "fmt"

    "time"

    "sync"

    )


func main() {

    var wg sync.WaitGroup

    wg.Add(1)

    go func() {

        time.Sleep(3 * time.Second)

        fmt.Println("hai")

        wg.Done()

    }()

    wg.Wait()

    return

}


查看完整回答
反对 回复 2023-07-10
  • 3 回答
  • 0 关注
  • 140 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信