您好,登錄后才能下訂單哦!
Go語言提供defer關(guān)鍵字,用于延遲調(diào)用,延遲到當(dāng)函數(shù)返回前被執(zhí)行,多用于資源釋放、解鎖以及錯(cuò)誤處理等操作。比如:
func main() { f, err := createFile("defer.txt") if err != nil { fmt.Println(err.Error()) return } defer closeFile(f) writeFile(f) } func createFile(filePath string) (*os.File, error) { f, err := os.Create(filePath) if err != nil { return nil, err } return f, nil } func writeFile(f *os.File) { fmt.Println("write file") fmt.Fprintln(f, "hello gopher!") } func closeFile(f *os.File) { fmt.Println("close file") f.Close() }
如果一個(gè)函數(shù)內(nèi)引用了多個(gè)defer,它們的執(zhí)行順序是怎么樣的呢?比如:
package main func main() { defer println("a") defer println("b") } 輸出: b a
如果函數(shù)中引入了panic函數(shù),那么延遲調(diào)用defer會(huì)不會(huì)被執(zhí)行呢?比如:
func main() { defer println("a") panic("d") defer println("b") } 輸出: a panic: d goroutine 1 [running]: panic(0x48a560, 0xc42000a340) /root/data/go/src/runtime/panic.go:500 +0x1a1 main.main() /root/data/workspace/src/defer/main.go:7 +0x107 exit status 2
日常開發(fā)中,一定要記住defer是在函數(shù)結(jié)束時(shí)才被調(diào)用的,如果應(yīng)用不合理,可能會(huì)造成資源浪費(fèi),給gc帶來壓力,甚至造成邏輯錯(cuò)誤,比如:
func main() { for i := 0;i < 10000;i++{ filePath := fmt.Sprintf("/data/log/%d.log", i) fp, err := os.Open(filePath) if err != nil{ continue } defef fp.Close() //這是要在main函數(shù)返回時(shí)才會(huì)執(zhí)行的,不是在循環(huán)結(jié)束后執(zhí)行,延遲調(diào)用,導(dǎo)致占用資源 //do stuff... } }
修改方案是直接調(diào)用Close函數(shù)或?qū)⑦壿嫹庋b成獨(dú)立函數(shù),比如:
func logAnalisys(p string){ fp, err := os.Open(p) if err != nil{ continue } defef fp.Close() //do stuff } func main() { for i := 0;i < 10000;i++{ filePath := fmt.Sprintf("/data/log/%d.log", i) logAnalisys(filePath) //將業(yè)務(wù)邏輯獨(dú)立封裝成函數(shù) } }
在性能方面,延遲調(diào)用花費(fèi)的代價(jià)也很大,因?yàn)檫@個(gè)過程包括注冊、調(diào)用等操作,還有額外的內(nèi)存開銷。比如:
package main import "testing" import "fmt" import "sync" var m sync.Mutex func test(){ m.Lock() m.Unlock() } func testCap(){ m.Lock() defer m.Unlock() } func BenchmarkTest(t *testing.B){ for i:= 0;i < t.N; i++{ test() } } func BenchmarkTestCap(t *testing.B){ for i:= 0;i < t.N; i++{ testCap() } } func main(){ resTest := testing.Benchmark(BenchmarkTest) fmt.Printf("BenchmarkTest \t %d, %d ns/op,%d allocs/op, %d B/op\n", resTest.N, resTest.NsPerOp(), resTest.AllocsPerOp(), resTest.AllocedBytesPerOp()) resTest = testing.Benchmark(BenchmarkTestCap) fmt.Printf("BenchmarkTestCap \t %d, %d ns/op,%d allocs/op, %d B/op\n", resTest.N, resTest.NsPerOp(), resTest.AllocsPerOp(), resTest.AllocedBytesPerOp()) } 輸出: BenchmarkTest 50000000, 27 ns/op,0 allocs/op, 0 B/op estCap 20000000, 112 ns/op,0 allocs/op, 0 B/op
在要求高性能的高并發(fā)場景下,應(yīng)避免使用延遲調(diào)用。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。