Golang實現(xiàn)超時機制讀取文件的方法示例
協(xié)程與通道
協(xié)程(Goroutine)是輕量級線程,可實現(xiàn)函數(shù)或方法與主程序流并行執(zhí)行。使用go關鍵字:go func(){}。通道是協(xié)程直接的通訊管道,主要用于在協(xié)程間傳輸數(shù)據(jù),即往通道寫數(shù)據(jù)、從通道讀數(shù)據(jù)。
通過chan關鍵字聲明通道,可以使用var或:=兩種方式聲明,也可以聲明待緩存的通道,語法如下:
channelName:= make(chan Type, n)
舉例:
dataStream := make(chan string, 1)
往通道寫數(shù)據(jù):
dataStream <- "data"
從通道讀數(shù)據(jù):
varName := <-dataStream
關閉通道:
close(dataStream)
Go 超時機制
超時對于連接到外部資源或需要限制執(zhí)行時間的場景來說非常重要。這是因為太長的服務器端處理將消耗太多的資源,導致并發(fā)性下降,甚至服務不可用。
利用select語句及并行協(xié)程實現(xiàn)超時,必須導入time包。然后使用time.After()參數(shù)創(chuàng)建通道,調用time.After(1 * time.Second)將在1秒后填充通道。下面示例通過通道和select實現(xiàn)超時:
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,調用函數(shù)模擬復雜業(yè)務,2秒后從非阻塞通道返回結果。select語句實現(xiàn)超時。results := <- dataChannel等待結果,time.After(1 * time.Second)語句1秒后返回值,因此select首先等待1秒,超過1秒將超時。
下面利用該機制實現(xiàn)讀取文件超時機制實現(xiàn)。
讀取整個文件
Go中讀整個文件一般使用ioutil/os包中的Read File()函數(shù),讀取整個文件值字節(jié)slice。ioutil包最好別用于讀取大文件,對于小文件完全夠用。
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
}
我們可以使用不同的超時時間進行測試:
go run main.go text.txt 1.0 go run main.go text.txt 0.9
按行讀文件
可以使用 bufio.Scanner 按行讀文件,使用bufio.NewScanner(file)構造函數(shù)創(chuàng)建Scanner,然后通過Scan()和Text()方法逐行讀取內容。使用Err()方法檢查讀取文件過程中的錯誤。
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()
}
當然也可以使用不同超時時間進行測試,如超時場景:
go run main.go test.txt 0.1 # Program execution out of time
按塊方式讀文件
對于非常大的文件使用塊方式讀取非常有用,無需把整個文件加載到內存中,每次讀取固定塊大小內容。下面readFileChunk函數(shù)中需要創(chuàng)建緩沖區(qū),每次讀取該緩沖區(qū)大小的內容,直到io.EOF錯誤出現(xiàn),表明已經(jīng)到達文件結尾。
緩沖區(qū)大小、目標文件以及超時時間作為函數(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)
}
總結
對于資源密集型程序正在執(zhí)行時,Golang超時機制是必要的,它有助于終止這種冗長的程序。本文通過示例展示了不同方式讀取文件的超時機制實現(xiàn)。
到此這篇關于Golang實現(xiàn)超時機制讀取文件的方法示例的文章就介紹到這了,更多相關Golang超時機制讀取文件內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang多線程爬蟲高效抓取大量數(shù)據(jù)的利器
Golang多線程爬蟲是一種高效抓取大量數(shù)據(jù)的利器。Golang語言天生支持并發(fā)和多線程,可以輕松實現(xiàn)多線程爬蟲的開發(fā)。通過使用Golang的協(xié)程和通道,可以實現(xiàn)爬蟲的高效并發(fā)抓取、數(shù)據(jù)處理和存儲2023-05-05
GO接收GET/POST參數(shù)及發(fā)送GET/POST請求的實例詳解
這篇文章主要介紹了GO接收GET/POST參數(shù)及發(fā)送GET/POST請求,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12

