栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

golang延时

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

golang延时

许多内置的带有返回值的函数无法进行延迟调用

在go语言中,调用自定义函数的结果值可以全部不存在(丢弃)。但是,对于具有非空白返回结果列表的内置函数,他们的调用的结果不可以抛弃,copy和recover例外。 换句话说,延迟执行函数的结果必须被抛弃,所以许多内置函数无法被延迟。

幸运的是,在实践中,很有偶需要延迟执行内置函数的地方。据我所知,只有append函数可能需要被延迟执行。这种情况下,我们可以把append包装到一个延迟执行函数里。

package main

import "fmt"

func main() {

s := []string{"a", "b", "c", "d"}

defer fmt.Println(s) // [a x y d]

// defer append(s[:1], "x", "y") // error

defer func() {

_ = append(s[:1], "x", "y")

}()

}

延迟函数值的时刻

延迟函数调用中的被调用函数可以是零函数值。对于这种情况,恐慌将在准备延迟调用被推入当前goroutine的延迟调用栈之前发生。

package main

import "fmt"

func main() {

defer fmt.Println("reachable")

var f func() // f is nil by default

defer f() // panic here

// The following lines are dead code.

fmt.Println("not reachable")

f = func() {}

}

在将延迟调用推入当前goroutine的延迟调用堆栈之前,还会计算延迟函数调用的参数

延迟调用使得代码清晰,并且bug少

import "os"

func withoutDefers(filepath string, head, body []byte) error {

f, err := os.Open(filepath)

if err != nil {

return err

}

_, err = f.Seek(16, 0)

if err != nil {

f.Close()

return err

}

_, err = f.Write(head)

if err != nil {

f.Close()

return err

}

_, err = f.Write(body)

if err != nil {

f.Close()

return err

}

err = f.Sync()

f.Close()

return err

}

func withDefers(filepath string, head, body []byte) error {

f, err := os.Open(filepath)

if err != nil {

return err

}

defer f.Close()

_, err = f.Seek(16, 0)

if err != nil {

return err

}

_, err = f.Write(head)

if err != nil {

return err

}

_, err = f.Write(body)

if err != nil {

return err

}

return f.Sync()

}

延迟函数调用导致的性能损失

使用延迟函数调用并不总是好的。到目前为止(Go 1.12),对于官方Go编译器,延迟函数调用将在运行时导致一些性能损失.

例如,在以下示例中,CounterB和IncreaseB方法比CounterA和IncreaseA方法更有效。

import "sync"

type T struct {

mu sync.Mutex

n int64

}

func (t *T) CounterA() int64 {

t.mu.Lock()

defer t.mu.Unlock()

return t.n

}

func (t *T) CounterB() (count int64) {

t.mu.Lock()

count = t.n

t.mu.Unlock()

return

}

func (t *T) IncreaseA() {

t.mu.Lock()

defer t.mu.Unlock()

t.n++

}

func (t *T) IncreaseB() {

t.mu.Lock()

t.n++ // this line will not panic for sure

t.mu.Unlock()

}

在B版本的函数中,我们应该保证Lock和Unlock调用之间的代码永远不会出现恐慌。通常,建议在实践中使用A版本功能。当我们真正关心所涉及功能的性能时,我们应该只采用B版本。

延迟函数调用导致的资源泄漏

非常大的延迟调用堆栈也可能消耗大量内存,并且未执行的延迟调用可能会阻止某些资源及时释放。例如,如果在调用以下函数时需要处理许多文件,则在函数退出之前将不会释放大量文件处理程序。

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

}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/945717.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号