2017-12-08 10 views
1

私はいくつかのことを学びたいと思っています。私はcsvファイルから読み込んだスクリプトを作成しようとしています。ファイルの行を処理するための効率的な方法

私はgoroutineがスキャナで行ごとにファイルから読み込み、行がチャンネルに送られ、異なるゴルーチンがチャンネルの内容を消費するように、パイプラインパターンに従っています。

私がやろうとしています何の例: https://gist.github.com/pkulak/93336af9bb9c7207d592

私の問題がある:csvファイル内のレコードがたくさんあります。私は結果的に行間で数学をしたい。 record1はr1であり、record2はr2であると言います。

ファイルを読むときは、私はr1です。次のスキャナループでは、私はr2を持っています。私はr1-r2が私のために有効な番号であるかどうかを見たいと思っています。はいの場合は、それらの間にいくつかの数学を行います。同じ方法でr3r4をチェックしてください。 r1-r2が有効でない場合、r2を気にせず、r1-r3などを実行してください。

ファイルの行をチャンネルに入れてチャンネルのコンテンツを処理した後、これを処理する必要がありますか?

並行性を損なわないような提案はありますか?

+2

、ファイルからの読み取りなど(またはネットワークから)がボトルネックになることがありあなたのアプリの中で、処理部分を並行させることから何も勝つことはできません。反対に、同時に処理を遅く複雑にするかもしれません。 – icza

+0

はい、しかし、行との作業(githubへのリンクから)は単純な操作ではなく、長い時間がかかる場合、コンカレントソリューションは意味をなさないです。 –

答えて

1

私はRead the lines into the work queue機能の中に「あなたにとってr1-r2有効な番号は何ですか」と判断すべきだと思います。

したがって、valid numbersのペアがないうちに、現在の行を読み、次の行を1行ずつ読み込む必要があります。あなたが得たら、このペアをworkQueueチャンネルの中に送り、次のペアを探します。

これは変更にあなたのコードです:

ファイルから読み込んだデータを処理するときに、特に、右の同時解決に飛び込むべきではありません
package main 

import (
    "bufio" 
    "log" 
    "os" 
    "errors" 
) 

var concurrency = 100 

type Pair struct { 
    line1 string 
    line2 string 
} 

func main() { 

    // It will be better to receive file-path from somewhere (like args or something like this) 
    filePath := "/path/to/file.csv" 

    // This channel has no buffer, so it only accepts input when something is ready 
    // to take it out. This keeps the reading from getting ahead of the writers. 
    workQueue := make(chan Pair) 

    // We need to know when everyone is done so we can exit. 
    complete := make(chan bool) 

    // Read the lines into the work queue. 
    go func() { 

     file, e := os.Open(filePath) 
     if e != nil { 
      log.Fatal(e) 
     } 
     // Close when the function returns 
     defer file.Close() 

     scanner := bufio.NewScanner(file) 

     // Get pairs and send them into "workQueue" channel 
     for { 
      line1, e := getNextCorrectLine(scanner) 
      if e != nil { 
       break 
      } 
      line2, e := getNextCorrectLine(scanner) 
      if e != nil { 
       break 
      } 
      workQueue <- Pair{line1, line2} 
     } 

     // Close the channel so everyone reading from it knows we're done. 
     close(workQueue) 
    }() 

    // Now read them all off, concurrently. 
    for i := 0; i < concurrency; i++ { 
     go startWorking(workQueue, complete) 
    } 

    // Wait for everyone to finish. 
    for i := 0; i < concurrency; i++ { 
     <-complete 
    } 
} 

func getNextCorrectLine(scanner *bufio.Scanner) (string, error) { 
    var line string 
    for scanner.Scan() { 
     line = scanner.Text() 
     if isCorrect(line) { 
      return line, nil 
     } 
    } 
    return "", errors.New("no more lines") 
} 

func isCorrect(str string) bool { 
    // Make your validation here 
    return true 
} 

func startWorking(pairs <-chan Pair, complete chan<- bool) { 
    for pair := range pairs { 
     doTheWork(pair) 
    } 

    // Let the main process know we're done. 
    complete <- true 
} 

func doTheWork(pair Pair) { 
    // Do the work with the pair 
} 
+0

返事をありがとう。だからあなたの提案は、ファイルからデータを読み込みながらフィルタリングし、フィルタリングされたコンテンツをチャンネルに送ることです。それも私の推測でした。あなたが書いたコードは、すべての行をseparetelyでチェックします。私は、それぞれではなく、2つの行の間で小切手を作る方法を考え出すのは苦労します。あなたの投稿は本当に役に立ちました! – paraflou

+0

この返信があなたの問題を解決するなら、あなたはそれを "便利"と "回答"としてマークすることができます:) –

関連する問題