国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

你有考慮過Defer Close() 的風(fēng)險嗎

開發(fā) 前端
作為一名 Gopher,我們很容易形成一個編程慣例:每當(dāng)有一個實現(xiàn)了 io.Closer 接口的對象 x 時,在得到對象并檢查錯誤之后,會立即使用 defer x.Close() 以保證函數(shù)返回時 x 對象的關(guān)閉 。以下給出兩個慣用寫法例子。 HTTP 請求

[[410667]]

本文轉(zhuǎn)載自微信公眾號「Golang技術(shù)分享」,作者機(jī)器鈴砍菜刀 。轉(zhuǎn)載本文請聯(lián)系Golang技術(shù)分享公眾號。

作為一名 Gopher,我們很容易形成一個編程慣例:每當(dāng)有一個實現(xiàn)了 io.Closer 接口的對象 x 時,在得到對象并檢查錯誤之后,會立即使用 defer x.Close() 以保證函數(shù)返回時 x 對象的關(guān)閉 。以下給出兩個慣用寫法例子。

HTTP 請求

  1. 1resp, err := http.Get("https://golang.google.cn/"
  2. 2if err != nil { 
  3. 3    return err 
  4. 4} 
  5. 5defer resp.Body.Close() 
  6. 6// The following code: handle resp 

訪問文件

  1. 1f, err := os.Open("/home/golangshare/gopher.txt"
  2. 2if err != nil { 
  3. 3    return err 
  4. 4} 
  5. 5defer f.Close() 
  6. 6// The following code: handle f 

存在問題

實際上,這種寫法是存在潛在問題的。defer x.Close() 會忽略它的返回值,但在執(zhí)行 x.Close() 時,我們并不能保證 x 一定能正常關(guān)閉,萬一它返回錯誤應(yīng)該怎么辦?這種寫法,會讓程序有可能出現(xiàn)非常難以排查的錯誤。

那么,Close() 方法會返回什么錯誤呢?在 POSIX 操作系統(tǒng)中,例如 Linux 或者 maxOS,關(guān)閉文件的 Close() 函數(shù)最終是調(diào)用了系統(tǒng)方法 close(),我們可以通過 man close 手冊,查看 close() 可能會返回什么錯誤

  1. 1ERRORS 
  2. 2     The close() system call will fail if: 
  3. 4     [EBADF]            fildes is not a valid, active file descriptor. 
  4. 6     [EINTR]            Its execution was interrupted by a signal. 
  5. 8     [EIO]              A previously-uncommitted write(2) encountered an 
  6. 9                        input/output error. 

錯誤 EBADF 表示無效文件描述符 fd,與本文中的情況無關(guān);EINTR 是指的 Unix 信號打斷;那么本文中可能存在的錯誤是 EIO。

EIO 的錯誤是指未提交讀,這是什么錯誤呢?

計算機(jī)存儲層次結(jié)構(gòu)

EIO 錯誤是指文件的 write() 的讀還未提交時就調(diào)用了 close() 方法。

上圖是一個經(jīng)典的計算機(jī)存儲器層級結(jié)構(gòu),在這個層次結(jié)構(gòu)中,從上至下,設(shè)備的訪問速度越來越慢,容量越來越大。存儲器層級結(jié)構(gòu)的主要思想是上一層的存儲器作為低一層存儲器的高速緩存。

CPU 訪問寄存器會非常之快,相比之下,訪問 RAM 就會很慢,而訪問磁盤或者網(wǎng)絡(luò),那意味著就是蹉跎光陰。如果每個 write() 調(diào)用都將數(shù)據(jù)同步地提交到磁盤,那么系統(tǒng)的整體性能將會極度降低,而我們的計算機(jī)是不會這樣工作的。當(dāng)我們調(diào)用 write() 時,數(shù)據(jù)并沒有立即被寫到目標(biāo)載體上,計算機(jī)存儲器每層載體都在緩存數(shù)據(jù),在合適的時機(jī)下,將數(shù)據(jù)刷到下一層載體,這將寫入調(diào)用的同步、緩慢、阻塞的同步轉(zhuǎn)為了快速、異步的過程。

這樣看來,EIO 錯誤的確是我們需要提防的錯誤。這意味著如果我們嘗試將數(shù)據(jù)保存到磁盤,在 defer x.Close() 執(zhí)行時,操作系統(tǒng)還并未將數(shù)據(jù)刷到磁盤,這時我們應(yīng)該獲取到該錯誤提示(只要數(shù)據(jù)還未落盤,那數(shù)據(jù)就沒有持久化成功,它就是有可能丟失的,例如出現(xiàn)停電事故,這部分?jǐn)?shù)據(jù)就永久消失了,且我們會毫不知情)。但是按照上文的慣例寫法,我們程序得到的是 nil 錯誤。

解決方案

我們針對關(guān)閉文件的情況,來探討幾種可行性改造方案

  • 第一種方案,那就是不使用 defer
  1.  1func solution01() error { 
  2.  2    f, err := os.Create("/home/golangshare/gopher.txt"
  3.  3    if err != nil { 
  4.  4        return err 
  5.  5    } 
  6.  6 
  7.  7    if _, err = io.WriteString(f, "hello gopher"); err != nil { 
  8.  8        f.Close() 
  9.  9        return err 
  10. 10    } 
  11. 11 
  12. 12    return f.Close() 
  13. 13} 

這種寫法就需要我們在 io.WriteString 執(zhí)行失敗時,明確調(diào)用 f.Close() 進(jìn)行關(guān)閉。但是這種方案,需要在每個發(fā)生錯誤的地方都要加上關(guān)閉語句 f.Close(),如果對 f 的寫操作 case 較多,容易存在遺漏關(guān)閉文件的風(fēng)險。

  • 第二種方案是,通過命名返回值 err 和閉包來處理
  1.  1func solution02() (err error) { 
  2.  2    f, err := os.Create("/home/golangshare/gopher.txt"
  3.  3    if err != nil { 
  4.  4        return 
  5.  5    } 
  6.  6 
  7.  7    defer func() { 
  8.  8        closeErr := f.Close() 
  9.  9        if err == nil { 
  10. 10            err = closeErr 
  11. 11        } 
  12. 12    }() 
  13. 13 
  14. 14    _, err = io.WriteString(f, "hello gopher"
  15. 15    return 
  16. 16} 

這種方案解決了方案一中忘記關(guān)閉文件的風(fēng)險,如果有更多 if err !=nil 的條件分支,這種模式可以有效降低代碼行數(shù)。

  • 第三種方案是,在函數(shù)最后 return 語句之前,顯示調(diào)用一次 f.Close()
  1.  1func solution03() error { 
  2.  2    f, err := os.Create("/home/golangshare/gopher.txt"
  3.  3    if err != nil { 
  4.  4        return err 
  5.  5    } 
  6.  6    defer f.Close() 
  7.  7 
  8.  8    if _, err := io.WriteString(f, "hello gopher"); err != nil { 
  9.  9        return err 
  10. 10    } 
  11. 11 
  12. 12    if err := f.Close(); err != nil { 
  13. 13        return err 
  14. 14    } 
  15. 15    return nil 
  16. 16} 

這種解決方案能在 io.WriteString 發(fā)生錯誤時,由于 defer f.Close() 的存在能得到 close 調(diào)用。也能在 io.WriteString 未發(fā)生錯誤,但緩存未刷新到磁盤時,得到 err := f.Close() 的錯誤,而且由于 defer f.Close() 并不會返回錯誤,所以并不擔(dān)心兩次 Close() 調(diào)用會將錯誤覆蓋。

  • 最后一種方案是,函數(shù) return 時執(zhí)行 f.Sync()
  1.  1func solution04() error { 
  2.  2    f, err := os.Create("/home/golangshare/gopher.txt"
  3.  3    if err != nil { 
  4.  4        return err 
  5.  5    } 
  6.  6    defer f.Close() 
  7.  7 
  8.  8    if _, err = io.WriteString(f, "hello world"); err != nil { 
  9.  9        return err 
  10. 10    } 
  11. 11 
  12. 12    return f.Sync() 
  13. 13} 

由于調(diào)用 close() 是最后一次獲取操作系統(tǒng)返回錯誤的機(jī)會,但是在我們關(guān)閉文件時,緩存不一定被會刷到磁盤上。那么,我們可以調(diào)用 f.Sync() (其內(nèi)部調(diào)用系統(tǒng)函數(shù) fsync )強(qiáng)制性讓內(nèi)核將緩存持久到磁盤上去。

  1.  1// Sync commits the current contents of the file to stable storage. 
  2.  2// Typically, this means flushing the file system's in-memory copy 
  3.  3// of recently written data to disk. 
  4.  4func (f *File) Sync() error { 
  5.  5    if err := f.checkValid("sync"); err != nil { 
  6.  6        return err 
  7.  7    } 
  8.  8    if e := f.pfd.Fsync(); e != nil { 
  9.  9        return f.wrapErr("sync", e) 
  10. 10    } 
  11. 11    return nil 
  12. 12} 

 

由于 fsync 的調(diào)用,這種模式能很好地避免 close 出現(xiàn)的 EIO。可以預(yù)見的是,由于強(qiáng)制性刷盤,這種方案雖然能很好地保證數(shù)據(jù)安全性,但是在執(zhí)行效率上卻會大打折扣。

 

責(zé)任編輯:武曉燕 來源: Golang技術(shù)分享
相關(guān)推薦

2023-10-04 17:25:01

面向接口編程

2020-07-14 07:48:19

Java對象JVM

2022-01-05 12:03:48

MySQL索引數(shù)據(jù)

2024-04-24 13:59:02

云原生應(yīng)用

2016-04-19 16:01:05

2015-10-26 09:52:26

bat裁員信息安全

2020-11-04 17:35:39

網(wǎng)絡(luò)安全漏洞技術(shù)

2020-06-20 14:09:01

信息安全數(shù)據(jù)技術(shù)

2015-01-14 09:33:07

2015-12-15 10:46:57

云計算風(fēng)險行業(yè)安全

2021-10-18 21:41:10

Go程序員 Defer

2019-08-14 05:35:08

2012-11-22 11:35:15

打印機(jī)

2010-12-21 11:31:09

2018-02-25 22:37:21

應(yīng)用開關(guān)Java

2022-06-15 15:23:03

實用型代幣加密貨幣以太坊

2022-04-28 08:12:29

函數(shù)調(diào)用進(jìn)程切換代碼

2023-03-13 13:36:00

Go擴(kuò)容切片

2017-11-27 06:30:25

IP耦合架構(gòu)

2019-04-11 18:46:22

APP手機(jī)應(yīng)用下載
點贊
收藏

51CTO技術(shù)棧公眾號

一区二区三区欧美在线| 国产日韩欧美电影在线观看| h动漫在线视频| 日韩成人免费电影| 91精品国产91久久久久久| 黑人巨大精品欧美一区二区桃花岛| 午夜精品久久久久久久久久| 日韩在线一级片| 奇米精品一区二区三区四区| 91在线观看网站| 日韩欧美久久| 久久精品精品电影网| 国产精品伦理| 亚洲国产天堂网精品网站| 国产视频福利在线| 亚洲一区二区三区精品在线| 噼里啪啦国语在线观看免费版高清版| 国产美女娇喘av呻吟久久| 亚洲国产精品久久久久久女王| 久久久xxx| 视频一区二区三区在线观看| 日韩激情一二三区| 亚洲欧美精品在线观看| 免费的国产精品| 亚洲天堂av免费在线观看| 首页综合国产亚洲丝袜| 欧美日韩电影一区二区| 日韩成人一区二区三区在线观看| 欧美日韩一区在线观看视频| 久久精选视频| 久久久一二三四| 成人国产电影网| 午夜精品久久久内射近拍高清| 91蜜桃网址入口| 一区二区三区 日韩| 中文字幕一区二区视频| 蜜桃视频中文字幕| 天天av天天翘天天综合网 | 欧美日韩国产中文字幕| 国产午夜视频在线观看| 日韩精品中文字幕在线一区| 欧美三级网站| 日韩一二三在线视频播| eeuss鲁片一区二区三区| 久久全国免费视频| 欧美丰满日韩| 久久精品国产综合精品| 国产美女精品一区二区三区| 色综合手机在线| 日韩人在线观看| gogo在线观看| 欧美成人免费小视频| 日本精品黄色| 日韩精品久久久| 欧美韩国一区二区| 成人18在线| 日韩中文娱乐网| 久久综合欧美| 一区二区三区四区| 国产精品久久99| jizz在线观看视频| 日韩在线视频网站| 欧美成熟视频| 日日摸日日碰夜夜爽无码| 亚洲成人资源在线| 少妇视频一区| 国产成人综合亚洲| 日韩电影在线观看网站| 成人淫片免费视频95视频| 欧美一区二区在线免费观看| 香港久久久电影| 蜜桃av久久久亚洲精品| 中文字幕的久久| 亚洲小说区图片区都市| 97人人做人人爱| 蜜臀av性久久久久蜜臀aⅴ流畅| 激情小说激情视频| 精品嫩草影院久久| 精品美女久久| 国产av熟女一区二区三区| 亚洲国产精品一区二区www | 一个色综合网站| 日本我和搜子同居的日子高清在线 | 中文有码一区| 亚洲欧洲免费视频| 国产精品无码一区二区在线| 亚洲日本成人在线观看| 一区二区三区日本久久久 | 国产精品无码电影在线观看| 亚洲欧美另类小说视频| 99自拍视频在线观看| 欧美美女操人视频| 激情综合亚洲| 九色丨porny丨自拍入口| 亚洲第一在线视频| 岛国成人av| 欧洲精品在线一区| 精品日韩视频在线观看| 亚洲精品18| 伊人网在线免费| 欧美三级蜜桃2在线观看| 国产99久久| 国产精品欧美激情在线观看| 欧美刺激午夜性久久久久久久| 成人在线免费观看网站| 男女无套免费视频网站动漫| 亚洲欧美国产视频| 玖玖国产精品视频| 在线观看视频你懂的| 欧美精品一二区| 国产精品1区2区3区| 欧美野外wwwxxx| 精品乱码一区二区三区| 91豆麻精品91久久久久久| 欧美sss在线视频| 成人av一级片| 一个色综合导航| 极品尤物av久久免费看| 美足av综合网| 麻豆久久久9性大片| 欧美在线观看视频一区二区三区 | 久久精品国产精品青草| mm1313亚洲国产精品美女| 9a蜜桃久久久久久免费| 亚洲不卡在线观看| 精品国产欧美日韩| 超清福利视频| 欧美在线观看一区二区三区| 国产欧美精品国产国产专区| 欧美影院视频| jizz欧美性11| 欧美中文在线字幕| 亚洲一二三四在线观看| 久久99国内| 一二三区在线视频| 国产69精品久久久久9999apgf| 色美美综合视频| 亚洲国产免费看| freemovies性欧美| 久久免费视频1| 精品成人佐山爱一区二区| 麻豆freexxxx性91精品| 欧美福利在线播放| 18禁免费无码无遮挡不卡网站| 久久精品视频中文字幕| 国产精品色噜噜| 黑人操亚洲人| 国产私人尤物无码不卡| 日韩精品欧美一区二区三区| 精品久久久久久无| 国产 欧美在线| 中文字幕久久精品一区二区 | 国产成人精品亚洲午夜麻豆| 91p九色成人| 又色又爽又高潮免费视频国产| 欧美黑人国产人伦爽爽爽| ...中文天堂在线一区| 国产日产精品一区二区三区四区的观看方式 | 欧美一区二区三区视频免费播放| 老牛影视一区二区三区| 一区二区三区四区日本视频| 99999精品视频| 国产精品久久电影观看| 色就色 综合激情| 麻豆久久久久久| 日韩精品一区二区三区中文| 亚洲精品666| 日韩aⅴ视频一区二区三区| 国产小视频国产精品| 亚洲欧洲制服丝袜| 在线看片日韩| 国产精品第一| ga∨成人网| 亚洲精品无人区| 超碰97人人做人人爱少妇| 亚洲超丰满肉感bbw| 久久精品国产第一区二区三区| 亚洲一区 二区| 午夜伦理在线| 男人天堂成人在线| 国精产品99永久一区一区| 日韩小视频网址| 欧美性生交xxxxx久久久| 国产精一区二区三区| 欧美日韩精品一区二区视频| 97超碰在线免费| 69ww免费视频播放器| 亚洲va韩国va欧美va精四季| 欧美专区在线播放| 亚洲国产精品福利| 亚洲欧美激情插| 日韩福利视频导航| 欧美在线关看| 不卡一本毛片| 色资源网在线观看| 91动漫在线看| 精品一区久久| 欧洲永久精品大片ww免费漫画| 亚洲精品国产suv| 色婷婷亚洲婷婷|