2013-04-20 3 views
1

lapply 함수 또는 루프에서 가비지 콜렉션을 수행하는 가장 빠른 방법은 무엇입니까? 내가보기에 명백한 것은 엄청나게 느려집니다. 내가 잘못하고 있니? 더 빠른 방법이 있습니까? 내 실제 유스 케이스에서는lapply에서 가비지 콜렉션 속도 향상

x <- 1:10000 
system.time(xx <- lapply(1:length(x), function(xi) sum(x[1:xi]))) 
user system elapsed 
    0.02 0.00 0.02 
system.time(xx <- lapply(1:length(x), function(xi) sum(x[1:xi], invisible(gc(v=FALSE))))) 
    user system elapsed 
    22.49 0.00 22.57 # a thousand times increase in time taken!! 

함수는 좀 더 복잡하고 각 인스턴스 후에 gc없이 실패. 덜 편리한 RAM이있는 컴퓨터로 전환 할 수 있으므로 더 빠른 gc 메서드를 사용할 수 있는지 궁금합니다.

x <- 1:10000 
system.time(x1 <- lapply(1:length(x), function(xi) sum(x[1:xi]))) 
    user system elapsed 
    3.47 0.00 3.56 
# define a function to make a sequence of a function followed by gc 
sum_gc <- function(x) sum(x); invisible(gc(v=FALSE)) 
system.time(x3 <- lapply(1:length(x), function(xi) sum_gc(x[1:xi]))) 
    user system elapsed 
    3.52 0.02 3.56 
: 약간의 물건을 정리 마틴 모건의 제안에 따라

UPDATEgc (지금 타이밍은 위에서 다른 이유는 다른 컴퓨터에서 작업)없이 lapply에 닫습니다 속도를 제공합니다

+1

매 반복마다 실제로 'gc'를 호출해야합니까? 100 단계 또는 그와 비슷한 것을 매번 호출하는 것으로 충분할 수 있습니다. RAM을 적게 사용하도록 기능을 최적화 할 수 있습니까? 물론 RAM을 더 확보 할 수 있다면 나쁜 생각은 아닙니다. – Roland

+4

하나는'gc'를 직접 호출 할 필요가 거의 없습니다! 나는 현재 예제에서 메모리 사용을 위해 아무 것도하지 않는다고 생각한다. 구문은 이상합니다. - gc에 대한 호출 결과를 sum의 인수로 제공하고 있습니다! 종종 메모리 및 성능 문제에 대한 해결책은 더 큰 시스템이 아닌 더 나은 알고리즘입니다. –

답변

3

답변이 아니지만 댓글보다 길었습니다. 벤,이

fun0 = function(x) sum(x, gc()) 

은 "x와 gc()"가 반환 한 값의 합계를 계산하는 함수를 정의합니다. 이

fun1 = function(x) sum(x); gc() 

은 x의 합계를 반환하는 함수를 정의합니다. gc()은 함수가 정의 된 후에 실행되지만 함수 정의의 일부는 아닙니다.

fun2 = function(x) { 
    result = sum(x) 
    gc() 
    result 
} 

는 x의 합을 계산하고, 내부에 존재하는 기능 result 변수에 저장하는 기능을 정의한다. 그런 다음 함수 gc()을 평가합니다. 그런 다음 result에 포함 된 값, 즉 x의 합을 반환합니다. 그것은 fun2 평가를 처음 이후, 정말 아무것도 성취하지 않습니다 fun2에서 gc() 호출 시간

test_case = 1:5 
identical(sum(test_case), fun0(test_case)) # FALSE 
identical(sum(test_case), fun1(test_case)) # TRUE, but no garbage collection 
identical(sum(test_case), fun2(test_case)) # TRUE 

뿐만 아니라 가치 비교 결과입니다. 할당되었지만 심볼과 더 이상 연관되지 않은 메모리가 없으므로 수집 할 쓰레기가 없습니다. 다음은 메모리를 할당하고, 사용하고, 참조를 제거한 다음 가비지 수집을 실행하여 메모리를 해제하는 경우입니다.

fun3 = function(x) { 
    m = rnorm(length(x)) 
    result = sum(m * x) 
    rm(m) 
    gc() 
    result 
} 

하지만 EXPLICIT 가비지 콜렉션은 여기에 유용한 아무것도하지 않습니다 - R가 사용할 수 있습니다보다 더 많은 메모리를 필요로 할 때 가비지 컬렉터가 자동으로 실행됩니다. fun3이 여러 번 호출 된 경우 각 호출에서 더 이상 기호로 참조되지 않는 메모리가 사용되므로 가비지 수집기가 자동으로 실행될 때 수집됩니다. gc()을 직접 호출하면 순진한 가비지 수집 전략 (항상 수행)이 R보다 낫다는 주장이 있습니다 (더 많은 메모리가 필요할 때 수행).

더 나은 가비지 수집기를 작성할 수있는 사람은 누구입니까?

그러나 여기에는 해당되지 않습니다.

나는 성능이나 메모리 문제에 직면하여 알고리즘과 구현을 살펴 보는 것이 종종 도움이된다고 언급했다. 나는 이것이 '장난감'의 예임을 알고 있지만 어쨌든 보자. 당신이 계산하는 것은 x의 원소들의 누적 합계입니다.나는

> x0 <- sapply(seq_along(test_case), fun4, test_case) 
> x0 
[1] 1 3 6 10 15 

을 제공하지만 R 메모리와 속도 모두의 측면에서이보다 효율적으로 수행하는 기능 cumsum을 가지고

fun4 = function(i, x) sum(x[seq_len(i)]) 
sapply(seq_along(test_case), fun4, test_case) 

로 구현을 쓴 것입니다.

> x1 <- cumsum(test_case) 
> identical(x0, x1) 
[1] TRUE 
> test_case = seq_len(10000) 
> system.time(x0 <- sapply(seq_along(test_case), fun4, test_case)) 
    user system elapsed 
    2.508 0.000 2.517 
> system.time(x1 <- cumsum(test_case)) 
    user system elapsed 
    0.004 0.000 0.002 
+0

네,'gc'의 자동적 특성과 논쟁에 대해 여러분이 말하는 것에 대해 잘 알고 있습니다 : http://stackoverflow.com/q/1467201/1036500 제 기능을 수정하고 설명 할 시간을 내 주셔서 감사합니다. 내 유스 케이스는'library (topicmodels); 데이터 (AssociatedPress); lapply (seq (20,40,10), function (d) LDA (AssociatedPress [1:20,], d))', 주제 수가 다른 모델의 목록을 작성합니다. 적은 수의 주제로도 괜찮지 만 점차적으로 (문서 등 1000 가지) 규모가 커지면 (또는 기계 시간으로 한 달이 지나면 참을성이 없어지면 ...). – Ben

+0

@Ben은'gc()'를 호출하면 그걸 __not__ 도와 줄 것입니다. – hadley

+0

더 많은 RAM/스왑이 여기에 최선의 선택입니까? – Ben