golang 函數三 (延遲調用)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Go語言提供defer關鍵字,用於延遲調用,延遲到當函數返回前被執行,多用於資源釋放、解鎖以及錯誤處理等操作。比如:

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()}

如果一個函數內引用了多個defer,它們的執行順序是怎麼樣的呢?比如:

package聽mainfunc聽main()聽{defer聽println("a")defer聽println("b")}輸出:ba


如果函數中引入了panic函數,那麼延遲調用defer會不會被執行呢?比如:

func聽main()聽{聽聽聽聽defer聽println("a")聽聽聽聽panic("d")聽聽聽聽defer聽println("b")}輸出:apanic:聽dgoroutine聽1聽[running]:panic(0x48a560,聽0xc42000a340)/root/data/go/src/runtime/panic.go:500聽+0x1a1main.main()/root/data/workspace/src/defer/main.go:7聽+0x107exit聽status聽2

日常開發中,一定要記住defer是在函數結束時才被調用的,如果應用不合理,可能會造成資源浪費,給gc帶來壓力,甚至造成邏輯錯誤,比如:

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函數返回時才會執行的,不是在迴圈結束後執行,延遲調用,導致佔用資源聽聽聽聽聽聽聽聽//do聽stuff...聽聽聽聽}}

修改方案是直接調用Close函數或將邏輯封裝成獨立函數,比如:

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)聽聽聽聽//將商務邏輯獨立封裝成函數聽聽聽聽}}


在效能方面,延遲調用花費的代價也很大,因為這個過程包括註冊、調用等操作,還有額外的記憶體開銷。比如:

package聽mainimport聽"testing"import聽"fmt"import聽"sync"var聽m聽sync.Mutexfunc聽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/opestCap聽聽20000000,聽112聽ns/op,0聽allocs/op,聽0聽B/op

在要求高效能的高並發情境下,應避免使用延遲調用。

本文出自 “博學於文,約之於禮” 部落格,轉載請與作者聯絡!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.