我写了一段代码来说明Go中的标准命令grep
,但速度是
远远落后于它,有人能给我任何进展吗?这是代码:
package main
import (
"bufio"
"fmt"
"log"
"os"
"strings"
"sync"
)
func parse_args() (file, pat string) {
if len(os.Args) < 3 {
log.Fatal("usage: gorep2 <file_name> <pattern>")
}
file = os.Args[1]
pat = os.Args[2]
return
}
func readFile(file string, to chan<- string) {
f, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
defer f.Close()
freader := bufio.NewReader(f)
for {
line, er := freader.ReadBytes('\n')
if er == nil {
to <- string(line)
} else {
break
}
}
close(to)
}
func grepLine(pat string, from <-chan string, result chan<- bool) {
var wg sync.WaitGroup
for line := range from {
wg.Add(1)
go func(l string) {
defer wg.Done()
if strings.Contains(l, pat) {
result <- true
}
}(string(line))
}
wg.Wait()
close(result)
}
func main() {
file, pat := parse_args()
text_chan := make(chan string, 10)
result_chan := make(chan bool, 10)
go readFile(file, text_chan)
go grepLine(pat, text_chan, result_chan)
var total uint = 0
for r := range result_chan {
if r == true {
total += 1
}
}
fmt.Printf("Total %d\n", total)
}
Go中的time
:
>>> time gogrep /var/log/task.log DEBUG
Total 21089
real 0m0.156s
user 0m0.156s
sys 0m0.015s
time
中的grep
:
>>> time grep DEBUG /var/log/task.log | wc -l
21089
real 0m0.069s
user 0m0.046s
sys 0m0.064s
答案 0 :(得分:16)
对于一个易于重现的基准,我计算了莎士比亚文本“和”的出现次数。
gogrep: $ go build gogrep.go && time ./gogrep /home/peter/shakespeare.txt and Total 21851 real 0m0.613s user 0m0.651s sys 0m0.068s grep: $ time grep and /home/peter/shakespeare.txt | wc -l 21851 real 0m0.108s user 0m0.107s sys 0m0.014s petergrep: $ go build petergrep.go && time ./petergrep /home/peter/shakespeare.txt and Total 21851 real 0m0.098s user 0m0.092s sys 0m0.008s
petergrep是用Go编写的。这很快。
package main
import (
"bufio"
"bytes"
"fmt"
"log"
"os"
)
func parse_args() (file, pat string) {
if len(os.Args) < 3 {
log.Fatal("usage: petergrep <file_name> <pattern>")
}
file = os.Args[1]
pat = os.Args[2]
return
}
func grepFile(file string, pat []byte) int64 {
patCount := int64(0)
f, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
if bytes.Contains(scanner.Bytes(), pat) {
patCount++
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
}
return patCount
}
func main() {
file, pat := parse_args()
total := grepFile(file, []byte(pat))
fmt.Printf("Total %d\n", total)
}
答案 1 :(得分:4)
Go正则表达式完全是utf-8,我认为这有一些开销。它们也有a different theoretical basis意味着它们总是在与输入长度成比例的时间内运行。值得注意的是,Go regexp并不像其他语言使用的pcre regexp那么快。如果你看benchmarks game shootouts for the regexp test,你就会明白我的意思。
如果您想要更快的速度,可以随时使用pcre library directly。
答案 2 :(得分:-1)
关于正则表达式解析中UTF-8相关性的数据点:我是一个长期使用的自定义perl5脚本,用于源代码grepping。我最近修改它以支持UTF-8,因此它可以匹配花哨的golang符号名称。它在重复测试中运行了一个完整的MAGNITUDE。因此,虽然golang regexp确实为其运行时的可预测性付出了代价,但我们还必须将UTF-8处理纳入等式。