Regex 如何使用pprof优化CSV加载程序?
我试图优化CSV加载过程,基本上就是在一个大的CSV文件中进行正则表达式搜索(+4GB-31033993条记录用于我的实验) 我设法构建了一个多处理逻辑来读取CSV,但当我使用Regex 如何使用pprof优化CSV加载程序?,regex,csv,go,concurrency,Regex,Csv,Go,Concurrency,我试图优化CSV加载过程,基本上就是在一个大的CSV文件中进行正则表达式搜索(+4GB-31033993条记录用于我的实验) 我设法构建了一个多处理逻辑来读取CSV,但当我使用pprof分析CPU配置文件时,我认为我的正则表达式搜索没有得到优化。你能帮我改进这段代码,让它能更快地读取CSV吗 以下是我目前的代码: package main import ( "bufio" "flag" "fmt" "log" "os" "regexp"
pprof
分析CPU配置文件时,我认为我的正则表达式搜索没有得到优化。你能帮我改进这段代码,让它能更快地读取CSV吗
以下是我目前的代码:
package main
import (
"bufio"
"flag"
"fmt"
"log"
"os"
"regexp"
"runtime"
"runtime/pprof"
"strings"
"sync"
)
func processFile(path string) [][]string {
file, err := os.Open(path)
if err != nil {
log.Println("Error:", err)
}
var pattern = regexp.MustCompile(`^.*foo.*$`)
numCPU := runtime.NumCPU()
jobs := make(chan string, numCPU+1)
fmt.Printf("Strategy: Parallel, %d Workers ...\n", numCPU)
results := make(chan []string)
wg := new(sync.WaitGroup)
for w := 1; w <= numCPU; w++ {
wg.Add(1)
go parseRecord(jobs, results, wg, pattern)
}
go func() {
scanner := bufio.NewScanner(file)
for scanner.Scan() {
jobs <- scanner.Text()
}
close(jobs)
}()
go func() {
wg.Wait()
close(results)
}()
lines := [][]string{}
for line := range results {
lines = append(lines, line)
}
return lines
}
func parseRecord(jobs <-chan string, results chan<- []string, wg *sync.WaitGroup, pattern *regexp.Regexp) {
defer wg.Done()
for j := range jobs {
if pattern.MatchString(j) {
x := strings.Split(string(j), "\n")
results <- x
}
}
}
func split(r rune) bool {
return r == ','
}
func main() {
f, err := os.Create("perf.data")
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
pathFlag := flag.String("file", "", `The CSV file to operate on.`)
flag.Parse()
lines := processFile(*pathFlag)
fmt.Println("loaded", len(lines), "records")
}
主程序包
进口(
“布菲奥”
“旗帜”
“fmt”
“日志”
“操作系统”
“regexp”
“运行时”
“运行时/pprof”
“字符串”
“同步”
)
func进程文件(路径字符串)[]字符串{
文件,错误:=os.Open(路径)
如果错误!=零{
log.Println(“错误:”,err)
}
var pattern=regexp.MustCompile(`^.*foo.*$`)
numpu:=runtime.numpu()
作业:=make(chan字符串,numpu+1)
fmt.Printf(“策略:并行,%d个工人…\n”,numCPU)
结果:=make(chan[]字符串)
wg:=新建(sync.WaitGroup)
对于w:=1;wMatchString查找字符串上的任何匹配项
所以你可以摆脱锚和通配符
在regexp引擎中,两端的通配符通常比较慢
示例显示了go 1.10中的这一点
package reggie
import (
"regexp"
"testing"
)
var pattern = regexp.MustCompile(`^.*foo.*$`)
var pattern2 = regexp.MustCompile(`foo`)
func BenchmarkRegexp(b *testing.B) {
for i := 0; i < b.N; i++ {
pattern.MatchString("youfathairyfoobar")
}
}
func BenchmarkRegexp2(b *testing.B) {
for i := 0; i < b.N; i++ {
pattern2.MatchString("youfathairyfoobar")
}
}
$ go test -bench=.
goos: darwin
goarch: amd64
BenchmarkRegexp-4 3000000 471 ns/op
BenchmarkRegexp2-4 20000000 101 ns/op
PASS
ok _/Users/jsandrew/wip/src/reg 4.031s
package reggie
进口(
“regexp”
“测试”
)
var pattern=regexp.MustCompile(`^.*foo.*$`)
var pattern2=regexp.MustCompile(`foo`)
func BenchmarkRegexp(b*testing.b){
对于i:=0;i
谢谢,这是一个我没有意识到的好技巧。这比阅读行31.606206481s要好得多。
-从这次更改中,你看到了在程序结构中还有什么可以改进的吗?-regrex模式将被动态地输入到更多的分析中,看看下一次尝试什么可能更好苏,我加了个正则表达式标签。