go を使用している割り当てについて、これから行うことの 1 つは、uniprot データベース ファイルを 1 行ずつ解析して、uniprot レコードを収集することです。
私はあまり多くのコードを共有したくないのですが、そのようなファイル (2.5 GB) を 48 秒 (time go-package を使用して測定) で正しく解析するコード スニペットがあります。ファイルを繰り返し解析し、レコード終了シグナル (完全なレコード) に到達するまでレコードに行を追加し、レコードのメタデータを作成します。次に、レコード文字列がヌルになり、新しいレコードが行ごとに収集されます。それから go-routine を使ってみようと思いました。
以前にスタックオーバーフローからいくつかのヒントを得て、元のコードに、メタデータの作成に関するすべてを処理する関数を単純に追加しました。
だから、コードはやっている
- 空のレコードを作成し、
- ファイルを繰り返し、レコードに行を追加します。
- 記録停止信号が見つかった場合 (これで完全な記録が得られました) - go ルーチンに渡してメタデータを作成します
- レコード文字列を null にして、2) から続行します。
sync.WaitGroup()
また、各ルーチンが終了するまで (最後に) 待機するように を追加しました。これにより、ゴルーチンが各レコードに作用している間も解析が続けられるため、データベースファイルの解析に費やされる時間が実際に短縮されると思いました。ただし、コードが 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)
}
}