淺析Go語言中的緩沖區(qū)及其在fmt包中的應(yīng)用
傳統(tǒng)的IO流程
在傳統(tǒng)的IO流程中,通常涉及以下幾個步驟:
- 打開文件或建立網(wǎng)絡(luò)連接:首先,需要打開文件或建立網(wǎng)絡(luò)連接,以便進(jìn)行讀取或?qū)懭氩僮?。這通常涉及到操作系統(tǒng)提供的系統(tǒng)調(diào)用,如
open
、socket
等。 - 讀取或?qū)懭霐?shù)據(jù):一旦文件或網(wǎng)絡(luò)連接打開,就可以進(jìn)行數(shù)據(jù)的讀取或?qū)懭氩僮?。讀取操作將從文件或網(wǎng)絡(luò)連接中獲取數(shù)據(jù),而寫入操作將將數(shù)據(jù)寫入文件或發(fā)送到網(wǎng)絡(luò)連接中。這些操作通常涉及到系統(tǒng)調(diào)用,如
read
和write
。 - 緩沖區(qū):為了提高IO性能,通常會使用緩沖區(qū)。緩沖區(qū)是一塊內(nèi)存區(qū)域,用于臨時存儲要讀取或?qū)懭氲臄?shù)據(jù)。數(shù)據(jù)首先被讀取到緩沖區(qū)中,然后從緩沖區(qū)中寫入到文件或網(wǎng)絡(luò)連接中,或者從緩沖區(qū)中讀取數(shù)據(jù)。
- 關(guān)閉文件或網(wǎng)絡(luò)連接:當(dāng)讀取或?qū)懭氩僮魍瓿珊?,需要關(guān)閉文件或網(wǎng)絡(luò)連接。這通常涉及到系統(tǒng)調(diào)用,如
close
。
在傳統(tǒng)的IO流程中,每次讀取或?qū)懭氩僮鞫紩婕暗较到y(tǒng)調(diào)用,這會導(dǎo)致較高的開銷。為了提高性能,通常會使用緩沖區(qū)來減少系統(tǒng)調(diào)用的次數(shù)。緩沖區(qū)可以一次讀取或?qū)懭攵鄠€數(shù)據(jù),從而減少了系統(tǒng)調(diào)用的開銷。
緩沖區(qū)
上面我們了解到緩沖區(qū)這個概念,那什么是緩沖區(qū)呢?
內(nèi)存緩沖區(qū)是計算機(jī)中的一種臨時存儲區(qū)域,用于暫時存儲數(shù)據(jù)。它通常用于提高數(shù)據(jù)讀寫的效率,減少對底層存儲設(shè)備的頻繁訪問。
緩沖區(qū)的主要目的是在數(shù)據(jù)的生產(chǎn)者和消費者之間起到一個中間層的作用。當(dāng)數(shù)據(jù)被生產(chǎn)者生成時,它首先被寫入緩沖區(qū),而不是直接寫入到目標(biāo)存儲設(shè)備。然后,消費者可以從緩沖區(qū)中讀取數(shù)據(jù)。
緩沖區(qū)的大小是有限的,一旦緩沖區(qū)被填滿,生產(chǎn)者必須等待消費者讀取數(shù)據(jù),以便為新的數(shù)據(jù)騰出空間。同樣,如果緩沖區(qū)為空,消費者必須等待生產(chǎn)者生成新的數(shù)據(jù)。
內(nèi)存緩沖區(qū)可以用于各種場景,比如:
- 文件讀寫:在讀取或?qū)懭氪笪募r,可以使用內(nèi)存緩沖區(qū)來提高讀寫性能。數(shù)據(jù)首先被讀取到緩沖區(qū)中,然后批量地寫入或讀取到磁盤上的文件。
- 網(wǎng)絡(luò)通信:在網(wǎng)絡(luò)通信中,數(shù)據(jù)通常需要經(jīng)過網(wǎng)絡(luò)協(xié)議的封裝和解析。使用內(nèi)存緩沖區(qū)可以將數(shù)據(jù)暫時存儲起來,以便進(jìn)行協(xié)議處理和網(wǎng)絡(luò)傳輸。
- 數(shù)據(jù)庫操作:在數(shù)據(jù)庫操作中,使用內(nèi)存緩沖區(qū)可以提高數(shù)據(jù)的讀寫性能。數(shù)據(jù)首先被寫入緩沖區(qū),然后批量地寫入到數(shù)據(jù)庫中,或者從緩沖區(qū)中讀取數(shù)據(jù)進(jìn)行查詢。
需要注意的是,內(nèi)存緩沖區(qū)只是一個臨時存儲區(qū)域,數(shù)據(jù)在緩沖區(qū)中并不是持久化的。一旦程序結(jié)束或緩沖區(qū)被清空,緩沖區(qū)中的數(shù)據(jù)就會丟失。因此,在使用內(nèi)存緩沖區(qū)時需要確保數(shù)據(jù)的正確性和一致性。
go緩沖區(qū)
在Go語言中,緩沖區(qū)的大小是由創(chuàng)建緩沖區(qū)時指定的參數(shù)決定的。在標(biāo)準(zhǔn)庫中,可以使用bufio
包提供的NewWriterSize
函數(shù)創(chuàng)建一個指定大小的緩沖區(qū)。
默認(rèn)情況下,bufio.Writer
的緩沖區(qū)大小為4096字節(jié)(4KB),即調(diào)用bufio.NewWriter
創(chuàng)建的緩沖區(qū)大小為4096字節(jié)。這是因為4096字節(jié)是一個常見的磁盤塊大小,對于大多數(shù)應(yīng)用場景來說,這個大小已經(jīng)足夠了。
如果需要自定義緩沖區(qū)的大小,可以使用bufio.NewWriterSize
函數(shù)來指定緩沖區(qū)的大小。例如,可以通過bufio.NewWriterSize(writer, 8192)
來創(chuàng)建一個大小為8192字節(jié)(8KB)的緩沖區(qū)。
為什么
為什么go編程中要設(shè)置緩沖區(qū)呢?其實我們上面都有提到:設(shè)置緩沖區(qū)的一個主要目的就是為了減少頻繁的IO操作。
在進(jìn)行IO操作時,例如讀取或?qū)懭胛募?,每次都直接操作底層的存儲設(shè)備(如磁盤或網(wǎng)絡(luò))可能會導(dǎo)致性能下降。這是因為每次IO操作都需要進(jìn)行系統(tǒng)調(diào)用,這涉及到內(nèi)核和用戶空間之間的上下文切換,以及硬件設(shè)備的訪問延遲。
通過使用緩沖區(qū),可以將數(shù)據(jù)暫時存儲在內(nèi)存中,而不是直接與底層存儲設(shè)備進(jìn)行交互。這樣可以將多個小的IO操作合并為一個大的IO操作,從而減少了系統(tǒng)調(diào)用的次數(shù)。這種批量處理的方式通常比頻繁的小IO操作更高效。
此外,緩沖區(qū)還可以提供更好的數(shù)據(jù)傳輸效率。當(dāng)數(shù)據(jù)被寫入緩沖區(qū)時,實際的IO操作可以被推遲到緩沖區(qū)被填滿或手動刷新緩沖區(qū)時才執(zhí)行。這樣可以減少IO操作的次數(shù),提高數(shù)據(jù)傳輸?shù)男省?/p>
go 緩沖區(qū)(Buffer)是分配在堆還是棧?
在Go語言中,緩沖區(qū)(Buffer)的申請是在堆上進(jìn)行的。
Go語言中的??臻g是有限的,而且棧上的內(nèi)存分配和釋放是由編譯器自動管理的,無法手動控制。因此,較大的緩沖區(qū)無法放在棧上進(jìn)行申請。
相反,Go語言中的堆空間是用于動態(tài)分配內(nèi)存的,可以手動控制內(nèi)存的申請和釋放。當(dāng)我們使用make
關(guān)鍵字創(chuàng)建一個切片或映射時,內(nèi)存就會在堆上進(jìn)行動態(tài)分配。而bufio
包中的緩沖區(qū)也是通過make
函數(shù)在堆上進(jìn)行申請的。
緩沖區(qū)的申請通常是在創(chuàng)建緩沖區(qū)時進(jìn)行的,例如使用bufio.NewWriter
或bufio.NewWriterSize
函數(shù)來創(chuàng)建一個緩沖區(qū)對象。這個過程會調(diào)用make
函數(shù)來分配足夠大小的內(nèi)存,并返回一個指向該內(nèi)存的指針。
fmt打印
示例
fmt.Println("Hello, world!"),大家平時用得最多了,這不就是打印輸出到控制臺嘛
當(dāng)執(zhí)行fmt.Println("Hello, world!")
命令時,會調(diào)用fmt
包內(nèi)的Println
函數(shù)來打印輸出。
首先,Println
函數(shù)會根據(jù)傳入的參數(shù)列表構(gòu)建一個字符串,并將其傳遞給Fprintln
函數(shù)。Fprintln
函數(shù)是fmt
包內(nèi)部的一個輔助函數(shù),它會將構(gòu)建的字符串寫入到標(biāo)準(zhǔn)輸出(即控制臺)。
在Fprintln
函數(shù)內(nèi)部,它會調(diào)用newPrinter
函數(shù)來創(chuàng)建一個pp
(printer)對象。pp
對象是printer
結(jié)構(gòu)體的實例,它包含了打印輸出的相關(guān)配置和狀態(tài)信息。
接下來,Fprintln
函數(shù)會調(diào)用pp.print
方法來實際執(zhí)行打印輸出的操作。在print
方法中,它會根據(jù)配置的格式化選項,將構(gòu)建的字符串寫入到pp.buf
緩沖區(qū)中。
如果緩沖區(qū)已滿,或者遇到換行符(\n
),print
方法會調(diào)用pp.write
方法將緩沖區(qū)的內(nèi)容寫入到標(biāo)準(zhǔn)輸出。write
方法會使用os.Stdout
作為目標(biāo),將緩沖區(qū)的內(nèi)容寫入到控制臺。
最后,Fprintln
函數(shù)會調(diào)用pp.free
方法來釋放pp
對象占用的內(nèi)存,以及清空緩沖區(qū)。
總結(jié)起來,當(dāng)執(zhí)行fmt.Println("Hello, world!")
命令時,fmt
包內(nèi)部會構(gòu)建打印輸出的字符串,并將其寫入到標(biāo)準(zhǔn)輸出。這個過程涉及到字符串的構(gòu)建、緩沖區(qū)的管理和標(biāo)準(zhǔn)輸出的寫入。通過使用printer
結(jié)構(gòu)體和相關(guān)方法,fmt
包實現(xiàn)了方便的打印輸出功能。
源碼查看
// ... func main() { fmt.Println("Hello, world!") } // fmt 包 // ... func Println(a ...any) (n int, err error) { return Fprintln(os.Stdout, a...) } // ... func Fprintln(w io.Writer, a ...any) (n int, err error) { p := newPrinter() p.doPrintln(a) n, err = w.Write(p.buf) p.free() return }
當(dāng)打印內(nèi)容很大怎么辦
當(dāng)打印的內(nèi)容超出了緩沖區(qū)的大小時,fmt
包會動態(tài)擴(kuò)展緩沖區(qū)的大小,以容納更大的數(shù)據(jù),并完整地輸出到標(biāo)準(zhǔn)輸出。
在執(zhí)行打印操作時,fmt
包會檢查緩沖區(qū)的剩余空間是否足夠容納當(dāng)前要打印的內(nèi)容。如果空間不足,fmt
包會自動擴(kuò)展緩沖區(qū)的大小,通常是將緩沖區(qū)的大小翻倍。
例如,在默認(rèn)情況下,fmt
包的緩沖區(qū)大小為4KB。如果要打印的內(nèi)容超過了4KB,fmt
包會自動將緩沖區(qū)擴(kuò)展到8KB,以容納更多的數(shù)據(jù)。如果仍然不夠,會繼續(xù)擴(kuò)展到16KB,以此類推,直到能夠容納所有的數(shù)據(jù)。
當(dāng)緩沖區(qū)大小足夠容納要打印的內(nèi)容時,fmt
包會將數(shù)據(jù)寫入緩沖區(qū)中。當(dāng)緩沖區(qū)滿了或者遇到換行符(\n
)時,fmt
包會將緩沖區(qū)的內(nèi)容寫入到標(biāo)準(zhǔn)輸出,確保完整地輸出所有的數(shù)據(jù)。
也就是說我有一個8k的打印內(nèi)容,而緩沖區(qū)大小為4KB,那么在第一次寫入緩沖區(qū)后,緩沖區(qū)將被填滿。此時,fmt
包會進(jìn)行一次IO操作,將緩沖區(qū)的內(nèi)容寫入標(biāo)準(zhǔn)輸出。
由于緩沖區(qū)已滿,第二次寫入操作將觸發(fā)另一次IO操作,將剩余的內(nèi)容寫入標(biāo)準(zhǔn)輸出。
因此,在這種情況下,fmt
包會進(jìn)行兩次IO操作,將完整的8KB內(nèi)容寫入標(biāo)準(zhǔn)輸出。第一次是在緩沖區(qū)填滿后,第二次是在第二次寫入時。
到此這篇關(guān)于淺析Go語言中的緩沖區(qū)及其在fmt包中的應(yīng)用的文章就介紹到這了,更多相關(guān)Go緩沖區(qū)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
從零封裝Gin框架實現(xiàn)數(shù)據(jù)庫初始化GORM
這篇文章主要為大家介紹了從零封裝Gin框架實現(xiàn)數(shù)據(jù)庫初始化GORM,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01簡化Go開發(fā)提高生產(chǎn)力的強(qiáng)大工具及使用詳解
作為?Go?開發(fā)人員,應(yīng)該都知道維持簡潔高效開發(fā)工作流程的重要性,為了提高工作效率和代碼質(zhì)量,簡化開發(fā)流程并自動執(zhí)行重復(fù)性任務(wù)至關(guān)重要,在本文中,我們將探討一些強(qiáng)大的工具和技術(shù),它們將簡化?Go?開發(fā)過程,助力您的編碼之旅2023-10-10Golang 統(tǒng)計字符串字?jǐn)?shù)的方法示例
本篇文章主要介紹了Golang 統(tǒng)計字符串字?jǐn)?shù)的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05基于GORM實現(xiàn)CreateOrUpdate方法詳解
這篇文章主要為大家介紹了基于GORM實現(xiàn)CreateOrUpdate方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10