2017-12-08 6 views
1

나는 배우려고 노력 중이며 csv 파일에서 읽는 스크립트를 만들려고 노력 중이며 일부 프로세스를 수행하고 결과를 얻습니다.파일 행을 효율적으로 처리하는 방법

나는 goroutine이 스캐너로 라인 당 파일을 읽으므로 라인이 채널로 전송되고 다른 goroutines이 채널 컨텐츠를 사용하도록 파이프 라인 패턴을 따른다.

내가 뭘하려고 오전의 예 : 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 쌍이없는 동안 다음 행을 하나씩 읽어야합니다. 가지고 계시면 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 검사하지 않습니다. 나는 각자가 아닌 두 줄 사이에서 수표를 만드는 법을 알아내는 데 어려움을 겪는다. 귀하의 게시물 정말 도움이되었다! – paraflou

+0

이 답장으로 문제가 해결되면 "유용"및 "답변"으로 표시 할 수 있습니다. –