使用Go,我有大型日志文件。目前我打开它们,创建一个新的扫描程序bufio.NewScanner
,然后for scanner.Scan()
循环遍历这些行。每行都通过处理函数发送,该函数将其与正则表达式匹配并提取数据。我想使用goroutines同时处理这个文件。我相信这可能比顺序遍历整个文件更快。
每个文件可能需要几秒钟,我想知道我是否可以一次处理10个文件中的单个文件。我相信如果需要我可以牺牲记忆力。我有~3gb,最大的日志文件可能是75mb。
我发现scanner
有一个.Split()
方法,您可以在其中提供自定义拆分功能,但我无法使用此方法找到一个好的解决方案。
我还尝试创建一片切片,使用scanner.Scan()
在扫描仪中循环并向每个切片添加scanner.Text()
。
例如:
// pseudocode because I couldn't get this to work either
scanner := bufio.NewScanner(logInfo)
threads := [[], [], [], [], []]
i := 0
for scanner.Scan() {
i = i + 1
if i > 5 {
i = 0
}
threads[i] = append(threads[i], scanner.Text())
}
fmt.Println(threads)
我是Go的新手,关注效率和性能。我想学习如何编写好的Go代码!任何帮助或建议都非常感谢。
答案 0 :(得分:3)
彼得给出了一个很好的起点,如果你想做一些像扇出一样的扇形模式,你可以做类似的事情:
package main
import (
"bufio"
"fmt"
"log"
"os"
"sync"
)
func main() {
file, err := os.Open("/path/to/file.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
lines := make(chan string)
// start four workers to do the heavy lifting
wc1 := startWorker(lines)
wc2 := startWorker(lines)
wc3 := startWorker(lines)
wc4 := startWorker(lines)
scanner := bufio.NewScanner(file)
go func() {
defer close(lines)
for scanner.Scan() {
lines <- scanner.Text()
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}()
merged := merge(wc1, wc2, wc3, wc4)
for line := range merged {
fmt.Println(line)
}
}
func startWorker(lines <-chan string) <-chan string {
finished := make(chan string)
go func() {
defer close(finished)
for line := range lines {
// Do your heavy work here
finished <- line
}
}()
return finished
}
func merge(cs ...<-chan string) <-chan string {
var wg sync.WaitGroup
out := make(chan string)
// Start an output goroutine for each input channel in cs. output
// copies values from c to out until c is closed, then calls wg.Done.
output := func(c <-chan string) {
for n := range c {
out <- n
}
wg.Done()
}
wg.Add(len(cs))
for _, c := range cs {
go output(c)
}
// Start a goroutine to close out once all the output goroutines are
// done. This must start after the wg.Add call.
go func() {
wg.Wait()
close(out)
}()
return out
}
答案 1 :(得分:2)
如果可以接受在行N之前处理行N + 1,则可以使用简单的扇出模式开始。 The Go blog解释了此更高级的模式,例如取消和粉丝。
请注意,这只是一个简单明了的起点。例如,您几乎肯定会在退出之前等待process
函数返回。这可以在上面提到的博客文章中解释。
package main
import "bufio"
func main() {
var sc *bufio.Scanner
lines := make(chan string)
go process(lines)
go process(lines)
go process(lines)
go process(lines)
for sc.Scan() {
lines <- sc.Text()
}
close(lines)
}
func process(lines <-chan string) {
for line := range lines {
// implement processing here
}
}