【发布时间】:2013-10-09 21:52:11
【问题描述】:
对于我们正在使用 go 的作业,我们要做的事情之一是逐行解析 uniprotdatabasefile 以收集 uniprot 记录。
我不想共享太多代码,但我有一个工作代码 sn-p 可以在 48 秒内正确解析这样的文件(2.5 GB)(使用时间 go-package 测量)。它迭代地解析文件并向记录添加行,直到达到记录结束信号(完整记录),并创建记录上的元数据。然后将记录字符串清空,并逐行收集新记录。然后我想我会尝试使用 go-routines。
我之前从 stackoverflow 得到了一些提示,然后在原始代码中我简单地添加了一个函数来处理与元数据创建有关的所有事情。
所以,代码在做
- 创建一个空记录,
- 迭代文件并在记录中添加行,
- 如果找到记录停止信号(现在我们有完整记录)- 将其交给 go 例程以创建元数据
- 清空记录字符串并从 2) 继续。
我还添加了sync.WaitGroup() 以确保我(最终)等待每个例程完成。我认为这实际上会减少解析数据库文件所花费的时间,因为它会继续解析,而 goroutine 会作用于每条记录。但是,代码似乎运行了 20 多分钟,表明出现问题或开销变得疯狂。有什么建议吗?
package main
import (
"bufio"
"crypto/sha1"
"fmt"
"io"
"log"
"os"
"strings"
"sync"
"time"
)
type producer struct {
parser uniprot
}
type unit struct {
tag string
}
type uniprot struct {
filenames []string
recordUnits chan unit
recordStrings map[string]string
}
func main() {
p := producer{parser: uniprot{}}
p.parser.recordUnits = make(chan unit, 1000000)
p.parser.recordStrings = make(map[string]string)
p.parser.collectRecords(os.Args[1])
}
func (u *uniprot) collectRecords(name string) {
fmt.Println("file to open ", name)
t0 := time.Now()
wg := new(sync.WaitGroup)
record := []string{}
file, err := os.Open(name)
errorCheck(err)
scanner := bufio.NewScanner(file)
for scanner.Scan() { //Scan the file
retText := scanner.Text()
if strings.HasPrefix(retText, "//") {
wg.Add(1)
go u.handleRecord(record, wg)
record = []string{}
} else {
record = append(record, retText)
}
}
file.Close()
wg.Wait()
t1 := time.Now()
fmt.Println(t1.Sub(t0))
}
func (u *uniprot) handleRecord(record []string, wg *sync.WaitGroup) {
defer wg.Done()
recString := strings.Join(record, "\n")
t := hashfunc(recString)
u.recordUnits <- unit{tag: t}
u.recordStrings[t] = recString
}
func hashfunc(record string) (hashtag string) {
hash := sha1.New()
io.WriteString(hash, record)
hashtag = string(hash.Sum(nil))
return
}
func errorCheck(err error) {
if err != nil {
log.Fatal(err)
}
}
【问题讨论】:
-
“把它交给一个 goroutine”是如何实现的?这可能很容易复制很多字节。一般来说,至少有一些实现是很好的。您的代码实际上是并行运行的(GOMAXPROCS >1)吗?每个元数据任务都有一个 goroutine 还是只有一个?
-
我添加了代码。我假设我的代码并行运行,并且为每个元数据处理创建了一个 go 例程(参见代码)
-
大通道缓冲区只是因为这里没有任何东西从通道中取出,否则一切都会快速休眠。
-
您确定 20 分钟后它实际上仍在处理文件,还是它完成了并且只是坐在那里等待? (我的观点是你的问题可能与性能无关——它可能被挂起。)我会试着记录你启动了多少个 goroutine,完成了多少,并确保在屏幕上打印一些东西点击 wg.Wait() 这样你就可以看到你是在等待哈希值生成还是仍在扫描文件。
标签: go