2016-06-19 3 views
1

F #으로 데이터 처리를하고 있습니다. 먼저 모든 파일을 디렉토리에 넣은 다음 각 파일을 처리하여 일부 데이터 구조를 생성합니다. 마지막으로 처리 된 데이터를 SQLite에 저장합니다. Seq을 사용하여 파일 이름을 저장 한 다음 각 파일에 대해 지연 프로세스를 수행하는 Seq.map에 파이프 전달을하는 경우이를 알고 있습니다. 그러나 메모리에있는 모든 파일을 포함하는 파일이 얼마나 많은지는 불가능합니다. 그런 다음 명령형 프로그래밍 언어로 하나의 파일을 읽고 처리 한 다음 저장하고 중간 미디어 데이터를 릴리스하고 다음 파일을 수행 할 수있었습니다. 물론 F #이 명령형 프로그래밍을 할 수는 있지만 Functional programming 스타일로 할 수있는 기회가 있는지 알고 싶습니다.처리 된 데이터를 순서대로 해제하십시오.

files 
|> Seq.map readFile 
|> Seq.map processContent 
|> Seq.map storeProcessResult 

위 코드는 내 의견을 나타냅니다. files에는 일련의 파일 이름이 들어 있습니다. 그런 다음 파일 내용을 읽고 구조로 처리 한 다음 결과를 데이터베이스에 저장합니다. 나는 게으른 행동 때문에 파일이 하나씩 읽혀지고 처리된다는 것을 안다. 그러나 언제 최종 데이터가 공개됩니까?

+1

오류가 있습니까? 재귀를 사용하여이를 처리 할 수 ​​있습니다. 아니면 고차 함수를 사용하고'use'로 파일을 열면됩니다. 데이터베이스에서 10GB를 채울 데이터를 쉽게 처리 할 수 ​​있습니다. – s952163

+2

그럼 Seq이 당신을 위해 일하지 않는 이유는 무엇입니까? 'Seq.map' 연산이 파일을 읽었을 때 내용이'Seq.fold'에 의해 처리되면, 한 번에 하나의 파일 만 메모리에 유지합니다. – FuleSnabel

+0

@FuleSnabel Seq에서 모든 처리 된 데이터가 공개된다는 것을 의미합니까? – holmescn

답변

2

분명히 readFile, processContent 및 storeProcessResult 함수 내부에서 일어나는 일을 알고있을 것입니다. @FuleSnabel은 자신의 코멘트에서 여러분은 파일을 처리하기 위해 fold (재귀)를 매핑하고 사용할 수 있다고 말했습니다.

다음은 메모리 소비의 차이를 확인하기 위해 수행 할 수있는 간단한 테스트입니다. 1000 만 개의 요소가있는 목록의 목록을 만들고 목록을 합친 다음 1 천만 개의 요소가있는 목록의 Seq을 만들고 목록을 합칩니다. 64 비트 FSI를 사용하고 있습니다.

이 1GB 메모리에 대한 사용 :

let z = [for i in 1..3 -> List.init 10000000 (fun _ -> 1)] 
let w = z |> List.map (fun x -> System.GC.Collect();List.sum x) 

이 만, 메모리의 몇 MB를 사용합니다 훨씬 덜 그것에 10000000 1 초에 목록에 하나라도 이상 :

let x = seq {for i in 1..3 -> List.init 10000000 (fun _ -> 1) } 
let y = x |> Seq.map (fun x -> System.GC.Collect(); List.sum x) 

이를 워크 플로에서 단 하나 (아마 쉬운) 부분입니다. 파일을 여는 경우 해당 파일도 닫아야합니다. 그러므로 위의 use 제안을 따르십시오. 그러나 나는 파일 시스템에 액세스하고 게으른 순서로 많은 양의 데이터를 처리하는 것이 몇 가지 문제를 일으킬 수 있다는 것을 알고 있습니다.이 경우에는 언제든지 프로파일 링하고 병목 현상이 어디에 있는지 볼 수 있습니다.

그런데 코드에서 GC를 직접 호출 할 필요가 없습니다. 중간 결과가 테스트에서 메모리 수를 오염시키지 않도록 방금했습니다.

관련 문제