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í)間的場(chǎng)景來說非常重要。這是因?yàn)樘L(zhǎng)的服務(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)行測(cè)試:
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)行測(cè)試,如超時(shí)場(chǎng)景:
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ī)制是必要的,它有助于終止這種冗長(zhǎng)的程序。本文通過示例展示了不同方式讀取文件的超時(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-07
go-micro微服務(wù)domain層開發(fā)示例詳解
這篇文章主要為大家介紹了go-micro微服務(wù)domain層開發(fā)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Golang 并發(fā)讀寫鎖的具體實(shí)現(xiàn)
Go語言中的sync.RWMutex提供了讀寫鎖機(jī)制,允許多個(gè)協(xié)程并發(fā)讀取共享資源,但在寫操作時(shí)保持獨(dú)占性,本文主要介紹了Golang 并發(fā)讀寫鎖的具體實(shí)現(xiàn),感興趣的可以了解一下2025-02-02
golang中http請(qǐng)求的context傳遞到異步任務(wù)的坑及解決
這篇文章主要介紹了golang中http請(qǐng)求的context傳遞到異步任務(wù)的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03

