我在go程序中对api进行了大量的Web调用,结果存储在数据库中(使用mgo)。 api调用是在单独的go例程上完成的。在其他例程中,我在更新数据库之前将信息从数据库中提取出来并进行处理。当放回数据时,设置一个标志,以便知道该数据已经过后处理,因此当程序要求数据库提供另一个条目以进行后处理时,数据库会将数据库交回标志complete
为设为false
。当该标志设置为true时,go例程将关闭:wg.done()
。
一切都很好,我有很多打印输出告诉我程序是如何进行的,但是在运行结束时我会得到一个包含大量相同内容的巨大堆栈跟踪:
goroutine 56731 [睡觉]:time.Sleep(0x12a05f200) /usr/local/Cellar/go/1.5/libexec/src/runtime/time.go:59 + 0xf9 gopkg.in/mgo%2ev2.(*mongoServer).pinger(0xc82601b420,0x1) /Users/alex/go/src/gopkg.in/mgo.v2/server.go:295 + 0x1b4由创建者 gopkg.in/mgo%2ev2.newServer /Users/alex/go/src/gopkg.in/mgo.v2/server.go:88 + 0x162
goroutine 56698 [睡眠]:time.Sleep(0x12a05f200) /usr/local/Cellar/go/1.5/libexec/src/runtime/time.go:59 + 0xf9 gopkg.in/mgo%2ev2.(*mongoServer).pinger(0xc82601bce0,0x1) /Users/alex/go/src/gopkg.in/mgo.v2/server.go:295 + 0x1b4由创建者 gopkg.in/mgo%2ev2.newServer /Users/alex/go/src/gopkg.in/mgo.v2/server.go:88 + 0x162
goroutine 56699 [睡眠]:time.Sleep(0x1dcd6500) /usr/local/Cellar/go/1.5/libexec/src/runtime/time.go:59 + 0xf9 gopkg.in/mgo%2ev2.(*mongoCluster).syncServersLoop(0xc8256425a0) /Users/alex/go/src/gopkg.in/mgo.v2/cluster.go:353 + 0x2b1由 gopkg.in/mgo%2ev2.newCluster /Users/alex/go/src/gopkg.in/mgo.v2/cluster.go:73 + 0x1a0
goroutine 56738 [睡眠]:time.Sleep(0x12a05f200) /usr/local/Cellar/go/1.5/libexec/src/runtime/time.go:59 + 0xf9 gopkg.in/mgo%2ev2.(*mongoServer).pinger(0xc82606fa40,0x1) /Users/alex/go/src/gopkg.in/mgo.v2/server.go:295 + 0x1b4由创建者 gopkg.in/mgo%2ev2.newServer /Users/alex/go/src/gopkg.in/mgo.v2/server.go:88 + 0x162
下面的所有内容中都有一件事,这是上面的堆栈跟踪中唯一不同的输出(上面只是一个示例,我的终端可以滚动回到开头有这么多)
goroutine 57201 [IO wait]:net.runtime_pollWait(0xedb6f0,0x72, 0xc82000a2c0) /usr/local/Cellar/go/1.5/libexec/src/runtime/netpoll.go:157 + 0x60 net。(* pollDesc).Wait(0xc827b0e5a0,0x72,0x0,0x0) /usr/local/Cellar/go/1.5/libexec/src/net/fd_poll_runtime.go:73+0x3a net。(* pollDesc).WaitRead(0xc827b0e5a0,0x0,0x0) /usr/local/Cellar/go/1.5/libexec/src/net/fd_poll_runtime.go:78 + 0x36 net。(* netFD).Read(0xc827b0e540,0xc828d61000,0x1000,0x1000,0x0, 0x754050,0xc82000a2c0) /usr/local/Cellar/go/1.5/libexec/src/net/fd_unix.go:232+0x23a net。(* conn).Read(0xc8260eac38,0xc828d61000,0x1000,0x1000,0x0,0x0, 0x0)/usr/local/Cellar/go/1.5/libexec/src/net/net.go:172 + 0xe4 net / http.noteEOFReader.Read(0x7960c0,0xc8260eac38,0xc82751fd38, 0xc828d61000,0x1000,0x1000,0xc82644dc20,0x0,0x0) /usr/local/Cellar/go/1.5/libexec/src/net/http/transport.go:1370+0x67 net / http。(* noteEOFReader).Read(0xc826116e60,0xc828d61000,0x1000, 0x1000,0xc827d1a770,0x0,0x0):126 + 0xd0 BUFIO。(*阅读器).fill伪(0xc82644d4a0) /usr/local/Cellar/go/1.5/libexec/src/bufio/bufio.go:97 + 0x1e9 bufio。(* Reader).Peek(0xc82644d4a0,0x1,0x0,0x0,0x0,0x0,0x0) /usr/local/Cellar/go/1.5/libexec/src/bufio/bufio.go:132 + 0xcc 净/ HTTP(* persistConn).readLoop(0xc82751fce0) /usr/local/Cellar/go/1.5/libexec/src/net/http/transport.go:876 + 0xf7 由net / http。(* Transport).dialConn创建 /usr/local/Cellar/go/1.5/libexec/src/net/http/transport.go:685 + 0xc78
我正在努力弄清楚它告诉我的是什么,它是否锁定写入数据库,例程是否关闭以及某些事情已经超时,我不知道。 我正在使用1.5 btw。
任何有关如何解释上述内容的帮助都会很棒。
与数据库对话的代码如下:
func (l *Ledger) addRaceToDatabase(race Race) { //true if added,
false if existed
session, err := mgo.Dial("127.0.0.1")
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("collection").C("races")
// Index
index := mgo.Index{
Key: []string{"id"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
}
err = c.EnsureIndex(index)
if err != nil {
panic(err)
}
result := Race{}
//if the race exists, don't add it to the database
err = c.Find(bson.M{"id": race.ID}).One(&result)
if err != nil {
//if there is an error there wasn't an entry so add this to the database
err = c.Insert(race)
if err != nil {
panic(err)
}
} else {
//if it does find an entry, it will print it
fmt.Println("FOUND: ", result.ID)
}
}
答案 0 :(得分:0)
看起来引用的逻辑是每次需要对它执行某些操作时拨打MongoDB,这不是在HTTP服务器中保持持续数据库通信的适当方式。
每次Dial
MongoDB服务器(或副本集或mongos)时,都会启动一些后台活动,以使集群拓扑在内存中保持最新状态,并保持连接池的清晰(请注意,在单个Dial
调用之后创建的所有会话将共享一个连接池。)
每次想要与数据库通信时调用Dial
意味着所有逻辑对于每个拨号都是独立的,并且在最后一个会话关闭后,后台活动可能需要一些时间才能关闭。
所以尽管它会起作用,但由于它必须再次学习使用的拓扑结构,它无法使用现有池中的连接,它也会产生不必要的背景流失,这就是你的工作效率非常低在你的回溯中观察。
有关如何在此上下文中更好地维护会话的一些想法,请参阅此主题: