2017-04-11 106 views
1

我正在尝试处理与MongoDB的重新连接。要做到这一点,我尝试三次执行每一项操作(如果它失败,io.EOF)golang如何推迟周期工作?

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 
} 

所以现在的问题是关于延迟。它会按照我的设想关闭所有会话,还是会以其他方式行事? 如果你知道一些好的做法来处理这种不同的方式,我会很乐意阅读它们。

回答

1

A Tour of Go

一个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 
    } 
} 
1

考虑以下program

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") 

} 

它将打印

after loop 1 
func 0 
func 1 
func 2 
after loop 2 
loop 2 
loop 1 
loop 0 

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

我建议将循环的内容封装到内联函数中。它将按照您的需要调用延期功能。