golang中延迟函数调用的知识点
个较大的延迟调用队列可能会消耗很多内存。 另外,某些资源可能因为某些调用被延迟的太久而未能被及时释放。
比如,如果下面的例子中的函数需要处理大量的文件,则在此函数退出之前,将有大量的文件句柄得不到释放。
func writeManyFiles(files []File) error { for _, file := range files { f, err := os.Open(file.path) if err != nil { return err } defer f.Close() _, err = f.WriteString(file.content) if err != nil { return err } err = f.Sync() if err != nil { return err } } return nil }
对于这种情形,我们应该使用一个匿名函数将需要及时执行延迟的调用包裹起来。比如,上面的函数可以改进为如下:
func writeManyFiles(files []File) error { for _, file := range files { if err := func() error { f, err := os.Open(file.path) if err != nil { return err } defer f.Close() // 将在此循环步内执行 _, err = f.WriteString(file.content) if err != nil { return err } return f.Sync() }(); err != nil { return err } } return nil }
writeManyFiles 和 writeManyFiles2 两个函数的主要区别在于错误处理和资源管理的方式。具体来说,writeManyFiles2 函数通过立即返回错误而不是在循环的外部处理错误,减少了函数调用栈的深度,并且在每次循环迭代中都立即关闭文件,这有助于减少文件描述符的占用时间,从而可能提高了效率。下面是两个函数的详细对比:
1,错误处理:
writeManyFiles 函数在循环中遇到错误时会立即返回错误,但是它在循环的外部处理错误,这意味着即使在遇到第一个错误后,循环仍然会继续执行,直到所有文件都被尝试打开和写入。
writeManyFiles2 函数使用了一个匿名函数来封装文件打开、写入和同步的过程,并且在每次循环迭代中,如果遇到错误就会立即返回,这减少了函数调用栈的深度,因为不需要在循环的外部再次检查错误。
2,资源管理:
在 writeManyFiles 函数中,defer f.Close() 语句在循环的外部,这意味着即使在遇到错误后,文件描述符仍然会保持打开状态,直到整个循环完成。这可能会导致文件描述符长时间占用,尤其是在处理大量文件时。
在 writeManyFiles2 函数中,defer f.Close() 语句在匿名函数内部,这意味着每次循环迭代后,如果文件成功写入并且同步,文件描述符会立即关闭。这样可以更快地释放资源,减少资源占用。
3,性能影响:
writeManyFiles 函数可能在处理大量文件时效率较低,因为它在循环外部处理错误,并且在所有文件处理完毕后才关闭文件描述符。
writeManyFiles2 函数通过在每次循环迭代后立即关闭文件描述符,减少了文件描述符的占用时间,这有助于提高性能,尤其是在处理大量文件时。
总的来说,writeManyFiles2 函数通过更有效的错误处理和资源管理,可能提供了更高的执行效率。然而,实际的性能差异还需要根据具体的使用场景和系统环境来确定,因为文件系统的性能、磁盘I/O速度、文件大小等因素都可能影响最终的性能表现。
本文来自博客园,作者:孙龙-程序员,转载请注明原文链接:https://www.cnblogs.com/sunlong88/p/18618922