mongodb - 从 channel 读取 SIGSEGV : segmentation violation

标签 mongodb go channel segmentation-fault

我尝试使用 go-client (mgo) 在 mongoDB 中插入文档。我创建了一个新的 mongo session ,以及两个用于通信 b/w go-routines 的 channel ,channel 用于同步 b/w readFilemain,其他的是将readFile中的文件读取的数据传递给db编写例程 insertTxn

type Txn struct {
    Date time.Time
    Amt  float64
}



func main() {
    session, err := mgo.Dial("localhost")
    if err != nil {
        panic(err)
    }
    defer session.Close()

    channel := make(chan bool)
    txnChannel := make(chan Txn, 1e4)

    go readFile(txnChannel, channel)
    go insertTxn(session, txnChannel)

    <-channel
    time.Sleep(time.Second * 10) // waiting for insertTxn to finish

    defer func() {
        if r := recover(); r != nil {
            fmt.Println(r)
        }
    }()
}

然后,启动 goroutine readFile,它开始从输入文件读取数据,并将数据写入 txnChannel channel 。完成后,它通过写入 channel channel 来标记完成。

func readFile(txnChannel chan<- Txn, channel chan<- bool) { // write only channel
        txnFile, err := os.Open("path/to/dir/txns.txt")
        if err != nil {
            panic(err)
        }
        txnReader := bufio.NewReader(txnFile)
        defer func() {
            txnFile.Close()
            channel <- true
        }()
        var data []string
        var txn Txn
        var dur int
        var str string
        for i := 0; i < 25*1e2; i++ {
            str, err = txnReader.ReadString('\n')
            str = strings.TrimSuffix(str, "\n")
            if err != nil {
                panic(err)
            }
            data = strings.Split(str, " ")
            txn.Amt, err = strconv.ParseFloat(data[1], 64)
            if err != nil {
                panic(err)
            }
            if err != nil {
                panic(err)
            }
            dur, err = strconv.Atoi(data[0])
            if err != nil {
                panic(err)
            }
            txn.Date = time.Now().Add(-time.Second * time.Duration(dur))
            txnChannel <- txn
        }
}

另一个 goroutine insertTxn,创建对 txn 集合的引用,并继续监听 txnChannel channel , 并将接收到的数据写入 mongo 集合。

func insertTxn(session *mgo.Session, txnChannel <-chan Txn) {
        txnColl := session.DB("happay").C("txns")
        for {
            select {
            case txn := <-txnChannel:
                if err := txnColl.Insert(txn).Error; err != nil {
                    panic(err)
                }
            }
        }
}

现在,程序崩溃,原因如下:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1151f27]

我认为问题可能是我一次又一次地使用相同的结构,但当我读到写入 channel 时确实按值复制,而不是按引用复制。所以,它应该工作。任何帮助将不胜感激。

最佳答案

问题的根源在于insertTxn()函数:

if err := txnColl.Insert(txn).Error; err != nil {
    panic(err)
}

Collection.Insert()返回一个error类型的值,你引用了它的Error方法,但是你没有调用它(调用它看起来像 Error() ,这将导致 string 类型的值无论如何都无法与 nil 进行比较... ),因此您的 err 变量将是一个函数值,如果 Collection.Insert() 返回一个明确的 nil 错误值,它会发生 panic 。

如果你想检查某个函数是否返回错误,不要调用它的 error.Error() 方法,只需像这样检查 error 值本身:

if err := txnColl.Insert(txn); err != nil {
    panic(err)
}

一些其他注意事项:

使用 sync.WaitGroup 等待 goroutines,time.Sleep() 对于演示可能没问题,但对于“生产”代码来说真的很糟糕。有关示例,请参阅 Prevent the main() function from terminating before goroutines finish in GolangSolving goroutines deadlock .

还在 main() 末尾注册一个 defer 函数来“捕获” panic 没有效果:

   defer func() {
        if r := recover(); r != nil {
            fmt.Println(r)
        }
    }()

这应该是 main() 中的第一次(或更早但绝对不是最后一次)调用。此外,如果您只是打印错误,则没有必要,因为还将打印未从中恢复的 panic 。如果您打算处理这种情况,请使用 recover()

同样在 readFile() 中读取文件时,您还应该检查 io.EOF,因为文件可能没有您预期的那么多行到,在这种情况下你可能会提前休息。

关于mongodb - 从 channel 读取 SIGSEGV : segmentation violation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50755655/

相关文章:

go - 如何优雅的关闭 channel ?

c# - MongoDB C# 驱动程序 - $ 与相同字段匹配两次

c# - MongoDB C# 查询字符串上的 'Like'

node.js - 在 mongo/mongoose 中一次连接到多个数据库

mongodb - Mongo 中 $center 和 $centerSphere 之间的区别?

google-app-engine - 我无法使用 google.golang.org/appengine 模块将 Go 模块部署到 App Engine

java - ReadableByteChannel.read(ByteBuffer dest) 读取上限为 8KB。为什么?

json - golang 从 json 字符串中获取 key 的有效方法/lib,并使用此 key 执行 geoip,然后将 geoip 信息添加到 json

algorithm - 递归创建嵌套结构

go - 如何实现一个channel和多个reader同时读取相同的数据?