導出csv方案優化
簡介
上一篇文章,筆者使用excel的一篇入門文章,在本文筆者將會繼續上一篇深入研究一下相關優化方案。
實驗數據,191944行記錄,csv文件總大小58m。
執行方案
不優化
直接全部讀出然后導出:
代碼
package main import ( "encoding/csv" "fmt" "log" "os" "time" ) var tFmt = "2006-01-02 15:04:05" func main() { content := readFile() fmt.Printf("%s - read file end......%d\n",time.Now().Format(tFmt),len(content)) exportFile(content) } func readFile() [][]string { //準備讀取文件 fileName := "RPT_NORMAL_D_共享審批效率.csv" fmt.Printf("%s - read file......\n",time.Now().Format(tFmt)) fs1, _ := os.Open(fileName) r1 := csv.NewReader(fs1) content, err := r1.ReadAll() if err != nil { log.Fatalf("can not readall, err is %+v", err) } return content } func exportFile(content [][]string) { fmt.Printf("%s - start export file......\n",time.Now().Format(tFmt)) // 1. 導出頭到文件1 f, err := os.Create("test.csv") if err != nil { panic(err) } defer f.Close() f.WriteString("\xEF\xBB\xBF")// 寫入UTF-8 BOM w := csv.NewWriter(f) //data := content[:1] w.WriteAll(content) w.Flush() fmt.Printf("%s - end export file......\n",time.Now().Format(tFmt)) }
測試日志,如下可以看出導出時間1秒內可以完成 :
# 數據整包一次導出 2021-07-24 15:30:28 - read file...... 2021-07-24 15:30:28 - read file end......191944 2021-07-24 15:30:28 - start export file...... 2021-07-24 15:30:28 - end export file......
時間優化
開幾個線程并發的寫文件,然后調用命令合并文件
執行腳本
go run main.go echo $(date )" - start merge file" cat temp1.csv temp2.csv temp3.csv temp4.csv> test.csv echo $(date )" - end merge file"
執行代碼
package main import ( "encoding/csv" "fmt" "log" "os" "strconv" "time" ) var tFmt = "2006-01-02 15:04:05" func main() { content := readFile() fmt.Printf("%s - read file end......%d\n",time.Now().Format(tFmt),len(content)) exportFile(content) time.Sleep(time.Millisecond*200) } func readFile() [][]string { //準備讀取文件 fileName := "RPT_NORMAL_D_共享審批效率.csv" fmt.Printf("%s - read file......\n",time.Now().Format(tFmt)) fs1, _ := os.Open(fileName) r1 := csv.NewReader(fs1) content, err := r1.ReadAll() if err != nil { log.Fatalf("can not readall, err is %+v", err) } return content } func exportFile(content [][]string) { fmt.Printf("%s - start export multiple file......\n",time.Now().Format(tFmt)) length := len(content) // 1. 導出頭到文件1 f, err := os.Create("test.csv") if err != nil { panic(err) } defer f.Close() f.WriteString("\xEF\xBB\xBF")// 寫入UTF-8 BOM w := csv.NewWriter(f) data := content[:1] w.WriteAll(data) // 2. 并發循環導出,一次100,000 (10萬數據) 到 1個文件,最終輸出n個10萬數據的文件 count := 1 pos :=1 for pos < length { maxPos := pos+50000 if maxPos > length { maxPos = length } temp := content[pos: maxPos ] go wiriteTempFile(pos,"temp"+strconv.Itoa(count)+".csv",temp) count++ pos += 50000 } // 3. 合并n個文件到文件1 w.Flush() //fmt.Printf("%s - export file success......\n",time.Now().Format(tFmt)) } func wiriteTempFile(pos int,file string,data [][] string) { fmt.Printf("len === %d , pos=%d \n",len(data),pos) f, err := os.Create(file) if err != nil { panic(err) } defer f.Close() //f.WriteString("\xEF\xBB\xBF") // 寫入UTF-8 BOM w := csv.NewWriter(f) w.WriteAll(data) w.Flush() }
# 啟動4個線程并發導出4個文件,然后調用命令合并文件 $ sh merge.sh 2021-07-24 16:30:06 - read file...... 2021-07-24 16:30:07 - read file end......191944 2021-07-24 16:30:07 - start export multiple file...... len === 50000 , pos=1 len === 50000 , pos=50001 len === 41943 , pos=150001 len === 50000 , pos=100001 Sat Jul 24 16:30:07 2021 - start merge file Sat Jul 24 16:30:08 2021 - end merge file
結論
50m級別,不管是多線程導出還是單線程全部導出處理對時間影響不明顯
在實際生產總,可以根據具體情況選擇解決方案:
1、源數據一次讀出,一次寫入文件導出,無限制條件
2、源數據分批讀出,分批寫入文件,優化內存和CPU,犧牲速度,增對超大文件,不放使用該方案設計離線導出
3、源數據分批多線程讀出,分批多線程寫入不同文件,合并文件,犧牲內存和CPU,爭取速度(文件不大情況下可能時間更慢)
空了嘗試一下G級別的文件,使用方法3的效果。
任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。