Golang實(shí)現(xiàn)超時(shí)機(jī)制讀取文件的方法示例
協(xié)程與通道
協(xié)程(Goroutine)是輕量級(jí)線程,可實(shí)現(xiàn)函數(shù)或方法與主程序流并行執(zhí)行。使用go關(guān)鍵字:go func(){}。通道是協(xié)程直接的通訊管道,主要用于在協(xié)程間傳輸數(shù)據(jù),即往通道寫數(shù)據(jù)、從通道讀數(shù)據(jù)。
通過chan關(guān)鍵字聲明通道,可以使用var或:=兩種方式聲明,也可以聲明待緩存的通道,語法如下:
channelName:= make(chan Type, n)
舉例:
dataStream := make(chan string, 1)
往通道寫數(shù)據(jù):
dataStream <- "data"
從通道讀數(shù)據(jù):
varName := <-dataStream
關(guān)閉通道:
close(dataStream)
Go 超時(shí)機(jī)制
超時(shí)對(duì)于連接到外部資源或需要限制執(zhí)行時(shí)間的場景來說非常重要。這是因?yàn)樘L的服務(wù)器端處理將消耗太多的資源,導(dǎo)致并發(fā)性下降,甚至服務(wù)不可用。
利用select語句及并行協(xié)程實(shí)現(xiàn)超時(shí),必須導(dǎo)入time包。然后使用time.After()參數(shù)創(chuàng)建通道,調(diào)用time.After(1 * time.Second)將在1秒后填充通道。下面示例通過通道和select實(shí)現(xiàn)超時(shí):
package main import ( "fmt" "time" ) func main() { dataChannel:= make(chan string, 1) go func() { time.Sleep(2 * time.Second) dataChannel <- "result 1" }() select { case results := <- dataChannel: fmt.Println(results) case <-time.After(1 * time.Second): fmt.Println("timeout 1") } }
首先創(chuàng)建緩存通道dataChannel,調(diào)用函數(shù)模擬復(fù)雜業(yè)務(wù),2秒后從非阻塞通道返回結(jié)果。select語句實(shí)現(xiàn)超時(shí)。results := <- dataChannel等待結(jié)果,time.After(1 * time.Second)語句1秒后返回值,因此select首先等待1秒,超過1秒將超時(shí)。
下面利用該機(jī)制實(shí)現(xiàn)讀取文件超時(shí)機(jī)制實(shí)現(xiàn)。
讀取整個(gè)文件
Go中讀整個(gè)文件一般使用ioutil/os包中的Read File()函數(shù),讀取整個(gè)文件值字節(jié)slice。ioutil包最好別用于讀取大文件,對(duì)于小文件完全夠用。
os包包含執(zhí)行參數(shù)數(shù)組Args,包括執(zhí)行命令的所有參數(shù),為字符串類型數(shù)組。
package main import ( "fmt" "io/ioutil" "os" "strconv" "time" ) func main() { filePath := os.Args[1] timeOut, _ := strconv.ParseFloat(os.Args[2], 64) // buffered channel of dataStream dataStream := make(chan string, 1) // Run ReadFileToString function in it's own goroutine and pass back it's // response into dataStream channel. go func() { data, _ := ReadFileToString(filePath) dataStream <- data close(dataStream) }() // Listen on dataStream channel AND a timeout channel - which ever happens first. select { case res := <-dataStream: fmt.Println(res) case <-time.After(time.Duration(timeOut) * time.Second): fmt.Println("Program execution out of time ") } } func ReadFileToString(file string) (string, error) { content, err := ioutil.ReadFile(file) // error encountered during reading the data if err != nil { return "", err } // convert bytes to string return string(content), nil }
我們可以使用不同的超時(shí)時(shí)間進(jìn)行測試:
go run main.go text.txt 1.0 go run main.go text.txt 0.9
按行讀文件
可以使用 bufio.Scanner 按行讀文件,使用bufio.NewScanner(file)構(gòu)造函數(shù)創(chuàng)建Scanner,然后通過Scan()和Text()方法逐行讀取內(nèi)容。使用Err()方法檢查讀取文件過程中的錯(cuò)誤。
package main import ( "bufio" "fmt" "log" "os" "strconv" "time" ) func main() { //get filepath and timeout on the terminal filePath := os.Args[1] timeOut, _ := strconv.ParseFloat(os.Args[2], 64) //creating channels dataStream := make(chan string, 1) readerr := make(chan error) // Run ReadFileLineByLine function in its own goroutine and pass back it's // response into dataStream channel. go ReadFileLineByLine(filePath, dataStream, readerr) loop: for { // select statement will block this thread until one of the three conditions below is met select { case data := <-dataStream: // Process each line fmt.Println(data) case <-time.After(time.Duration(timeOut) * time.Second): fmt.Println("Program execution out of time ") break loop case err := <-readerr: if err != nil { log.Fatal(err) } break loop } } } func ReadFileLineByLine(filePath string, data chan string, er chan error) { // open file file, err := os.Open(filePath) if err != nil { fmt.Println(err) } // close the file at the end of the program defer file.Close() // read the file line by line using scanner scanner := bufio.NewScanner(file) for scanner.Scan() { data <- scanner.Text() } close(data) // close causes the range on the channel to break out of the loop er <- scanner.Err() }
當(dāng)然也可以使用不同超時(shí)時(shí)間進(jìn)行測試,如超時(shí)場景:
go run main.go test.txt 0.1 # Program execution out of time
按塊方式讀文件
對(duì)于非常大的文件使用塊方式讀取非常有用,無需把整個(gè)文件加載到內(nèi)存中,每次讀取固定塊大小內(nèi)容。下面readFileChunk函數(shù)中需要?jiǎng)?chuàng)建緩沖區(qū),每次讀取該緩沖區(qū)大小的內(nèi)容,直到io.EOF錯(cuò)誤出現(xiàn),表明已經(jīng)到達(dá)文件結(jié)尾。
緩沖區(qū)大小、目標(biāo)文件以及超時(shí)時(shí)間作為函數(shù)參數(shù),其他邏輯與上面示例一致:
package main import ( "fmt" "io" "log" "os" "strconv" "time" ) func main() { dataStream := make(chan string, 1) filePath := os.Args[1] timeOut, _ := strconv.ParseFloat(os.Args[2], 64) chunkSize, _ := strconv.Atoi(os.Args[3]) go readFileChunk (filePath, dataStream, int64(chunkSize)) select { case resultData := <- dataStream: fmt.Println(resultData) case <-time.After(time.Duration(timeOut) * time.Millisecond): fmt.Println("timeout") } } func readFileChunk(filePath string, data chan string, chunkSize int64) { // open file f, err := os.Open(filePath) if err != nil { log.Fatal(err) } // remember to close the file at the end of the program defer f.Close() buf := make([]byte, chunkSize) for { readTotal, err := f.Read(buf) if err != nil && err != io.EOF { log.Fatal(err) } if err == io.EOF { break } data <- string(buf[:readTotal]) } close(data) }
總結(jié)
對(duì)于資源密集型程序正在執(zhí)行時(shí),Golang超時(shí)機(jī)制是必要的,它有助于終止這種冗長的程序。本文通過示例展示了不同方式讀取文件的超時(shí)機(jī)制實(shí)現(xiàn)。
到此這篇關(guān)于Golang實(shí)現(xiàn)超時(shí)機(jī)制讀取文件的方法示例的文章就介紹到這了,更多相關(guān)Golang超時(shí)機(jī)制讀取文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang使用embed引入靜態(tài)文件的實(shí)例代碼
Golang embed是Go 1.16版本中引入的一項(xiàng)新功能,它可以使嵌入文件更容易,通常,在Go中嵌入文件需要使用文件系統(tǒng)或者第三方包,而使用embed可以更加便捷地嵌入文件,從而方便地訪問文件的內(nèi)容,本文介紹了Golang使用embed引入靜態(tài)文件,需要的朋友可以參考下2024-06-06使用go語言實(shí)現(xiàn)Redis持久化的示例代碼
redis 是一個(gè)內(nèi)存數(shù)據(jù)庫,如果你把進(jìn)程殺掉,那么里面存儲(chǔ)的數(shù)據(jù)都會(huì)消失,那么這篇文章就是來解決 redis 持久化的問題,本文給大家介紹了使用go語言實(shí)現(xiàn)Redis持久化,需要的朋友可以參考下2024-07-07go-micro微服務(wù)domain層開發(fā)示例詳解
這篇文章主要為大家介紹了go-micro微服務(wù)domain層開發(fā)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Golang 并發(fā)讀寫鎖的具體實(shí)現(xiàn)
Go語言中的sync.RWMutex提供了讀寫鎖機(jī)制,允許多個(gè)協(xié)程并發(fā)讀取共享資源,但在寫操作時(shí)保持獨(dú)占性,本文主要介紹了Golang 并發(fā)讀寫鎖的具體實(shí)現(xiàn),感興趣的可以了解一下2025-02-02golang中http請(qǐng)求的context傳遞到異步任務(wù)的坑及解決
這篇文章主要介紹了golang中http請(qǐng)求的context傳遞到異步任務(wù)的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03