golang如何循环延迟工作?

StT*_*mur 5 go deferred-execution

我正在尝试处理与 MongoDB 的重新连接。为此,我尝试将每个操作执行三次(以防因 io.EOF 失败)

type MongoDB struct {
    session *mgo.Session
    DB      *mgo.Database
}

func (d MongoDB) performWithReconnect(collection string, 
operation func(*mgo.Collection) error) error {
    var err error
    for i := 0; i < 3; i++ {
        session := d.session.Copy()
        defer session.Close()
        err = operation(session.DB(Config.MongoDb).C(collection))
        if err == io.EOF{
            continue
        }
        if err == nil{
            return err
        }
    }
    return err
}
Run Code Online (Sandbox Code Playgroud)

所以问题是关于延迟。它会像我想象的那样关闭所有会话还是会以其他方式表现?如果您知道一些处理这种不同方式的良好实践,我将很乐意阅读它们。

Grz*_*Żur 6

考虑以下程序

package main

import (
    "fmt"
)

func print(s string, i int) {
    fmt.Println(s, i)
}

func main() {

    for i := 0; i < 3; i++ {
        defer print("loop", i)
    }

    fmt.Println("after loop 1")

    for i := 0; i < 3; i++ {
        func(i int) {
            defer print("func", i)
        }(i)
    }

    fmt.Println("after loop 2")

}
Run Code Online (Sandbox Code Playgroud)

它将打印

after loop 1
func 0
func 1
func 2
after loop 2
loop 2
loop 1
loop 0
Run Code Online (Sandbox Code Playgroud)

延迟的函数调用将被放入堆栈中,然后在周围函数的末尾以相反的顺序执行。在你的情况下,这将是非常糟糕的,因为你将有连接等待关闭。

我建议将循环的内容包装到内联函数中。它会按照您的需要调用延迟函数。


Fli*_*mzy 2

来自围棋之旅

defer 语句推迟函数的执行,直到周围的函数返回。

因此,在您的代码中,您将创建三个(相同的)延迟函数,这些函数都将在函数退出时运行。

如果需要defer在循环内运行,则必须将其放在函数内。这可以在匿名函数中完成:

for i := 0; i < 3; i++ {
    err := func() error {
        session := d.session.Copy()
        defer session.Close()
        return operation(session.DB(Config.MongoDb).C(collection))
    }()
    if err == io.EOF {
        continue
    }
    if err != nil {
        return err
    }
}
Run Code Online (Sandbox Code Playgroud)