2016-08-20 3 views
4

내가지도를 만들 때처럼 코드의 조각을 가지고 : 내 객체 생성이지도를 사용하여 다음스칼라 불변의지도 느린

val map = gtfLineArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap 

:

case class MyObject(val attribute1: String, val attribute2: Map[String:String]) 

을 나는 수백만을 읽고 있어요 반복자를 사용하여 MyObjects로 변환합니다.

MyObject("1", map) 

처럼 나는 2'000'000 항목에 대해 1 시간보다 더 많은, 정말 느린 할 때.

는 내가 객체 생성에서지도를 제거하지만, 여전히 나는 분할 과정 (1 절) 수행

val map = gtfLineArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap 
MyObject("1", null) 

그리고 스크립트 미만 1 분에서 실행 과정을. 2 천만 개 항목에 해당합니다.

어떤 프로파일 링을하고 객체가 생성 될 때 객체 맵에 val map 사이의 할당이 진행되는 것이 느껴집니다. 내가 뭘 놓치고 있니?

it.map(cretateNewObject).toList 
: 당신이 내 코드를 볼 경우

(가) 내부 오브제로 각 라인을 변환 2,000,000 이상의 라인, 내가 반복하는 내 자신의 반복 처리를 설명 :

업데이트 문제를보다 잘 설명하기

이 반복자는 모든 행을 반복하고 함수 createNewObject을 사용하여 내 객체로 변환합니다.

dk14는 큰 메모리를 사용하여 실제로 실제로 빠릅니다. 성능 문제는 내

`crateNewObject(val line:String)` 

이 함수 내에서 내 함수가 라인을

`class MyObject(val attribute1:String, val attribute2:Map[String, String])` 

객체를 생성하고 첫

`val attributeArr = line.split("\t")` 

배열의 첫 번째 속성 레코드가있다 할 것입니다 내 개체의 attribute1과 두 번째 특성은

입니다.
`val map = attributeArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap` 

맵의 요소 수만 인쇄하면 프로그램이 2 분 만에 종료됩니다. 새 오브젝트 행에 맵을 전달하면 MyObject(attribute1, map) 프로그램이 실제로 느립니다.

+0

두 번째 경우에는 어디에서나 val map을 사용하지 않으므로 컴파일러는 그 행에 코드를 버리고 아무 것도 분리하지 않습니다. – Kolmar

+0

안녕하세요 @kolman 왜냐하면'gtfLineArr (8) .split (";") map (_ split "\" "). {case Array (k, v) => (k, v)} .toMap' 분할을 계산하고 그 결과를 Map으로 변환합니다. 실제로, gtfLineArr (8) .split (";"). map (_ split "\" "). {case Array (k, v) => (k, v)} .toMap.size'를 만들고 결과를 출력하면 Map이 생성되었음을 의미하는 1 분입니다. 내 의심스러운 것은지도가 새 객체에 전달되면 문제를 만드는 "일부"변환을 수행한다는 것입니다. – ypriverol

+0

당신의 코드는 무엇을하고 있습니까? 시간은 아마도이 줄에 쓰이지 않을 것입니다. – Dima

답변

3

(0 to 2000000).toList(0 to 2000000).map(x => x -> x).toMap은 충분한 메모리를 제공하면 비슷한 성능을 보입니다 (-Xmx4G - 4 기가 바이트). toMap 구현은 복제에 대한 많은 부분을 차지하므로 많은 메모리가 "할당"/ "할당 취소"되고 있습니다. 따라서 메모리 부족의 경우 GC가 과도하게 사용됩니다.

(0 to 2000000).toList을 128MB로 실행하려고하면 몇 초가 걸렸지 만 (0 to 2000000).map(x => x -> x).toMap은 10 % GC 작업 (VisualVM)으로 2 분 이상 걸리고 메모리가 부족하여 사망했습니다.

그러나 내가 시도했을 때 -Xmx4G 모두 매우 빠릅니다.


P. toMap이 반복적으로 요소를 접두사 트리에 추가하기 때문에 모든 요소 당 많은 수 (Array.copy)를 복제해야합니다 (https://github.com/scala/scala/blob/99a82be91cbb85239f70508f6695c6b21fd3558c/src/library/scala/collection/immutable/HashMap.scala#L321).

그래서, toMap 반복적으로 (메모리 부족 경우) MarkAndSweep 갈 GC 원인 메모리 할당, 많이 필요 꽤 자주 Array.copy을하고 나아가서 updated0을, 일 (2,000,000 회) (느린 가비지 컬렉션이다) 대부분의 시간 (jconsole에서 볼 수있는 한).


해결 방법 : 아파치 스파크 (또는 배치 지향지도-감소 프레임 워크)와 같은 데이터 세트를 사용 뭔가 더 복잡한 작업을해야하는 경우 메모리를 증가 여부 (-Xmx/-Xms JVM 매개 변수) 또는 처리 할 귀하의 데이터를 분산 방식으로

+0

나는'.toMap'이 소비된다는 것을 알고 있습니다. 그러나, 만약 yo가 예제를 보았다면, 각 항목에 대해서만 연산이 수행됩니다. – ypriverol

+0

매번 Map [String, String]'으로 수집되고 map이 객체에 전달되는 것처럼 보이는 프로파일 링을 몇 차례하고 있습니다. (2 백만개의 항목 각각에 대해) char []에서 String으로의 변환이 수행됩니다 . – ypriverol

+0

내 예제에서 말한 것처럼 실행하려고하는 실제 코드는 다음과 같습니다. – ypriverol