导出csv方案优化
【摘要】 简介上一篇文章,笔者使用excel的一片入门文章,在本文笔者将会继续上一篇深入研究一下相关优化方案。实验数据,191944行记录,csv文件总大小58m。 执行方案 不优化直接全部读出然后导出:代码package mainimport ( "encoding/csv" "fmt" "log" "os" "time")var tFmt = "2006-01-02 15:04:05"func ...
简介
上一篇文章,笔者使用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的效果。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)