淺析Go語言中的緩沖區(qū)及其在fmt包中的應用
傳統(tǒng)的IO流程
在傳統(tǒng)的IO流程中,通常涉及以下幾個步驟:
- 打開文件或建立網(wǎng)絡連接:首先,需要打開文件或建立網(wǎng)絡連接,以便進行讀取或寫入操作。這通常涉及到操作系統(tǒng)提供的系統(tǒng)調用,如
open
、socket
等。 - 讀取或寫入數(shù)據(jù):一旦文件或網(wǎng)絡連接打開,就可以進行數(shù)據(jù)的讀取或寫入操作。讀取操作將從文件或網(wǎng)絡連接中獲取數(shù)據(jù),而寫入操作將將數(shù)據(jù)寫入文件或發(fā)送到網(wǎng)絡連接中。這些操作通常涉及到系統(tǒng)調用,如
read
和write
。 - 緩沖區(qū):為了提高IO性能,通常會使用緩沖區(qū)。緩沖區(qū)是一塊內存區(qū)域,用于臨時存儲要讀取或寫入的數(shù)據(jù)。數(shù)據(jù)首先被讀取到緩沖區(qū)中,然后從緩沖區(qū)中寫入到文件或網(wǎng)絡連接中,或者從緩沖區(qū)中讀取數(shù)據(jù)。
- 關閉文件或網(wǎng)絡連接:當讀取或寫入操作完成后,需要關閉文件或網(wǎng)絡連接。這通常涉及到系統(tǒng)調用,如
close
。
在傳統(tǒng)的IO流程中,每次讀取或寫入操作都會涉及到系統(tǒng)調用,這會導致較高的開銷。為了提高性能,通常會使用緩沖區(qū)來減少系統(tǒng)調用的次數(shù)。緩沖區(qū)可以一次讀取或寫入多個數(shù)據(jù),從而減少了系統(tǒng)調用的開銷。
緩沖區(qū)
上面我們了解到緩沖區(qū)這個概念,那什么是緩沖區(qū)呢?
內存緩沖區(qū)是計算機中的一種臨時存儲區(qū)域,用于暫時存儲數(shù)據(jù)。它通常用于提高數(shù)據(jù)讀寫的效率,減少對底層存儲設備的頻繁訪問。
緩沖區(qū)的主要目的是在數(shù)據(jù)的生產者和消費者之間起到一個中間層的作用。當數(shù)據(jù)被生產者生成時,它首先被寫入緩沖區(qū),而不是直接寫入到目標存儲設備。然后,消費者可以從緩沖區(qū)中讀取數(shù)據(jù)。
緩沖區(qū)的大小是有限的,一旦緩沖區(qū)被填滿,生產者必須等待消費者讀取數(shù)據(jù),以便為新的數(shù)據(jù)騰出空間。同樣,如果緩沖區(qū)為空,消費者必須等待生產者生成新的數(shù)據(jù)。
內存緩沖區(qū)可以用于各種場景,比如:
- 文件讀寫:在讀取或寫入大文件時,可以使用內存緩沖區(qū)來提高讀寫性能。數(shù)據(jù)首先被讀取到緩沖區(qū)中,然后批量地寫入或讀取到磁盤上的文件。
- 網(wǎng)絡通信:在網(wǎng)絡通信中,數(shù)據(jù)通常需要經(jīng)過網(wǎng)絡協(xié)議的封裝和解析。使用內存緩沖區(qū)可以將數(shù)據(jù)暫時存儲起來,以便進行協(xié)議處理和網(wǎng)絡傳輸。
- 數(shù)據(jù)庫操作:在數(shù)據(jù)庫操作中,使用內存緩沖區(qū)可以提高數(shù)據(jù)的讀寫性能。數(shù)據(jù)首先被寫入緩沖區(qū),然后批量地寫入到數(shù)據(jù)庫中,或者從緩沖區(qū)中讀取數(shù)據(jù)進行查詢。
需要注意的是,內存緩沖區(qū)只是一個臨時存儲區(qū)域,數(shù)據(jù)在緩沖區(qū)中并不是持久化的。一旦程序結束或緩沖區(qū)被清空,緩沖區(qū)中的數(shù)據(jù)就會丟失。因此,在使用內存緩沖區(qū)時需要確保數(shù)據(jù)的正確性和一致性。
go緩沖區(qū)
在Go語言中,緩沖區(qū)的大小是由創(chuàng)建緩沖區(qū)時指定的參數(shù)決定的。在標準庫中,可以使用bufio
包提供的NewWriterSize
函數(shù)創(chuàng)建一個指定大小的緩沖區(qū)。
默認情況下,bufio.Writer
的緩沖區(qū)大小為4096字節(jié)(4KB),即調用bufio.NewWriter
創(chuàng)建的緩沖區(qū)大小為4096字節(jié)。這是因為4096字節(jié)是一個常見的磁盤塊大小,對于大多數(shù)應用場景來說,這個大小已經(jīng)足夠了。
如果需要自定義緩沖區(qū)的大小,可以使用bufio.NewWriterSize
函數(shù)來指定緩沖區(qū)的大小。例如,可以通過bufio.NewWriterSize(writer, 8192)
來創(chuàng)建一個大小為8192字節(jié)(8KB)的緩沖區(qū)。
為什么
為什么go編程中要設置緩沖區(qū)呢?其實我們上面都有提到:設置緩沖區(qū)的一個主要目的就是為了減少頻繁的IO操作。
在進行IO操作時,例如讀取或寫入文件,每次都直接操作底層的存儲設備(如磁盤或網(wǎng)絡)可能會導致性能下降。這是因為每次IO操作都需要進行系統(tǒng)調用,這涉及到內核和用戶空間之間的上下文切換,以及硬件設備的訪問延遲。
通過使用緩沖區(qū),可以將數(shù)據(jù)暫時存儲在內存中,而不是直接與底層存儲設備進行交互。這樣可以將多個小的IO操作合并為一個大的IO操作,從而減少了系統(tǒng)調用的次數(shù)。這種批量處理的方式通常比頻繁的小IO操作更高效。
此外,緩沖區(qū)還可以提供更好的數(shù)據(jù)傳輸效率。當數(shù)據(jù)被寫入緩沖區(qū)時,實際的IO操作可以被推遲到緩沖區(qū)被填滿或手動刷新緩沖區(qū)時才執(zhí)行。這樣可以減少IO操作的次數(shù),提高數(shù)據(jù)傳輸?shù)男省?/p>
go 緩沖區(qū)(Buffer)是分配在堆還是棧?
在Go語言中,緩沖區(qū)(Buffer)的申請是在堆上進行的。
Go語言中的??臻g是有限的,而且棧上的內存分配和釋放是由編譯器自動管理的,無法手動控制。因此,較大的緩沖區(qū)無法放在棧上進行申請。
相反,Go語言中的堆空間是用于動態(tài)分配內存的,可以手動控制內存的申請和釋放。當我們使用make
關鍵字創(chuàng)建一個切片或映射時,內存就會在堆上進行動態(tài)分配。而bufio
包中的緩沖區(qū)也是通過make
函數(shù)在堆上進行申請的。
緩沖區(qū)的申請通常是在創(chuàng)建緩沖區(qū)時進行的,例如使用bufio.NewWriter
或bufio.NewWriterSize
函數(shù)來創(chuàng)建一個緩沖區(qū)對象。這個過程會調用make
函數(shù)來分配足夠大小的內存,并返回一個指向該內存的指針。
fmt打印
示例
fmt.Println("Hello, world!"),大家平時用得最多了,這不就是打印輸出到控制臺嘛
當執(zhí)行fmt.Println("Hello, world!")
命令時,會調用fmt
包內的Println
函數(shù)來打印輸出。
首先,Println
函數(shù)會根據(jù)傳入的參數(shù)列表構建一個字符串,并將其傳遞給Fprintln
函數(shù)。Fprintln
函數(shù)是fmt
包內部的一個輔助函數(shù),它會將構建的字符串寫入到標準輸出(即控制臺)。
在Fprintln
函數(shù)內部,它會調用newPrinter
函數(shù)來創(chuàng)建一個pp
(printer)對象。pp
對象是printer
結構體的實例,它包含了打印輸出的相關配置和狀態(tài)信息。
接下來,Fprintln
函數(shù)會調用pp.print
方法來實際執(zhí)行打印輸出的操作。在print
方法中,它會根據(jù)配置的格式化選項,將構建的字符串寫入到pp.buf
緩沖區(qū)中。
如果緩沖區(qū)已滿,或者遇到換行符(\n
),print
方法會調用pp.write
方法將緩沖區(qū)的內容寫入到標準輸出。write
方法會使用os.Stdout
作為目標,將緩沖區(qū)的內容寫入到控制臺。
最后,Fprintln
函數(shù)會調用pp.free
方法來釋放pp
對象占用的內存,以及清空緩沖區(qū)。
總結起來,當執(zhí)行fmt.Println("Hello, world!")
命令時,fmt
包內部會構建打印輸出的字符串,并將其寫入到標準輸出。這個過程涉及到字符串的構建、緩沖區(qū)的管理和標準輸出的寫入。通過使用printer
結構體和相關方法,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 }
當打印內容很大怎么辦
當打印的內容超出了緩沖區(qū)的大小時,fmt
包會動態(tài)擴展緩沖區(qū)的大小,以容納更大的數(shù)據(jù),并完整地輸出到標準輸出。
在執(zhí)行打印操作時,fmt
包會檢查緩沖區(qū)的剩余空間是否足夠容納當前要打印的內容。如果空間不足,fmt
包會自動擴展緩沖區(qū)的大小,通常是將緩沖區(qū)的大小翻倍。
例如,在默認情況下,fmt
包的緩沖區(qū)大小為4KB。如果要打印的內容超過了4KB,fmt
包會自動將緩沖區(qū)擴展到8KB,以容納更多的數(shù)據(jù)。如果仍然不夠,會繼續(xù)擴展到16KB,以此類推,直到能夠容納所有的數(shù)據(jù)。
當緩沖區(qū)大小足夠容納要打印的內容時,fmt
包會將數(shù)據(jù)寫入緩沖區(qū)中。當緩沖區(qū)滿了或者遇到換行符(\n
)時,fmt
包會將緩沖區(qū)的內容寫入到標準輸出,確保完整地輸出所有的數(shù)據(jù)。
也就是說我有一個8k的打印內容,而緩沖區(qū)大小為4KB,那么在第一次寫入緩沖區(qū)后,緩沖區(qū)將被填滿。此時,fmt
包會進行一次IO操作,將緩沖區(qū)的內容寫入標準輸出。
由于緩沖區(qū)已滿,第二次寫入操作將觸發(fā)另一次IO操作,將剩余的內容寫入標準輸出。
因此,在這種情況下,fmt
包會進行兩次IO操作,將完整的8KB內容寫入標準輸出。第一次是在緩沖區(qū)填滿后,第二次是在第二次寫入時。
到此這篇關于淺析Go語言中的緩沖區(qū)及其在fmt包中的應用的文章就介紹到這了,更多相關Go緩沖區(qū)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
一文帶你掌握Go語言并發(fā)模式中的Context的上下文管理
在?Go?的日常開發(fā)中,Context?上下文對象無處不在,無論是處理網(wǎng)絡請求、數(shù)據(jù)庫操作還是調用?RPC?等場景,那你真的熟悉它的正確用法嗎,隨著本文一探究竟吧2023-05-05Golang微服務框架Kratos實現(xiàn)Kafka消息隊列的方法
消息隊列是大型分布式系統(tǒng)不可缺少的中間件,也是高并發(fā)系統(tǒng)的基石中間件,所以掌握好消息隊列MQ就變得極其重要,在本文當中,您將了解到:什么是消息隊列?什么是Kafka?怎樣在微服務框架Kratos當中應用Kafka進行業(yè)務開發(fā),需要的朋友可以參考下2023-09-09Golang如何編寫內存高效及CPU調優(yōu)的Go結構體
這篇文章主要介紹了Golang如何編寫內存高效及CPU調優(yōu)的Go結構體,結構體是包含多個字段的集合類型,用于將數(shù)據(jù)組合為記錄2022-07-07