我在golang中有两个关于延迟语句的例子,第一个是不正确的,第二个是正确的。但我认为他们有同样的问题,在我看来,我认为第二个仍然存在文件描述符耗尽的风险,任何人都可以帮助我澄清为什么第二个是正确的?谢谢!
例1:
for _, filename := range filenames {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close() // NOTE: risky; could run out of file descriptors
// ...process f...
}
例2:
for _, filename := range filenames {
if err := doFile(filename); err != nil {
return err
}
}
func doFile(filename string) error {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
// ...process f...
}
答案 0 :(得分:3)
当封闭函数返回时,延迟函数运行。 Spec: Defer statements:
“defer”语句调用一个函数,该函数的执行被推迟到周围函数返回的那一刻,因为周围的函数执行return statement,到达function body的末尾,或者因为相应的goroutine是panicking。
在您的第一个示例中,您使用了一个for
循环,其中您使用defer
语句,但延迟函数将不会在迭代结束时执行,仅在{{1}之后} loop(当封闭函数结束时)。这意味着您在for
循环内打开的所有文件将保持打开状态,直到“结束”。如果for
包含一千个有效的文件名,则循环将(尝试)在开始关闭任何文件之前打开一千个文件。
在您的第二个示例中,您将处理文件的“外包”发送到单独的功能。在此函数中使用filenames
根本不同,因为当此函数返回时,将首先调用延迟函数(defer
)。因此,在您的第二个示例中,无论File.Close()
包含多少元素,最多只有1个文件由发布的代码打开。