꽤 오랜 시간이 걸릴 R 코드를 돌린다면…

어느정도 R을 사용해본 사람은 알텐데, R언어는 스레드를 제공하지 않는다. 이 때문에 쉘에서의 작업은 대부분 동기적(sync) 방식으로 동작한다. 이 때문에 발생하는 문제는 바로 시간이 오래 걸리는 작업이 실행될 경우인데, 필자의 경우 R쉘에서 Hadoop관련 잡을 돌리기도 하고 데이터베이스와 연동해 쿼리를 실행하기도 해 이런 작업이 실행될 때 기다리거나 다른 주제의 일을 하곤한다.

하나의 분석 작업을 하기 위해 다양한 툴을 사용할 수 있기에 크게 고민하지 않고 이런 한계를 돌파할 생각을 하지 않았는데, 한 팀분이 이 문제에 대해서 효과적인 방법이 없냐고 문의를 해와 고민을 하게 되었고 좋은 방법을 찾아서 공유하는 바이다.

R에서 parallel패키지가 추가된게 약 2년 정도 되었는데, 개인적으로 멀티노드에서의 분산 처리가 가능하게 한 snow통합은 몇번의 시행착오 끝에 사용하지 않기로 마음먹은지 오래다. 뭐 이를 설명하자면 길어지니 다음 기회에 설명할 수 있도록 해보고….

정답을 이야기 하자면 .. parallel패키지에서 제공하는 mcparallel()함수를 사용하면 가능하다. 이 함수의 동작방식은 프로세스 fork기반으로 동작하고 현재 수행되는 R프로세스의 객체를 모두 공유하는(사실은 copy-on-write 방식) 자식 프로세스를 생성해 이 자식에게 잡을 할당하는 것이다. 따라서 이 기능은 윈도우 계열의 OS에서는 동작하지 않으며 분석 머신으로 맥이나 리눅스를 사용하는걸 추천하는 많은 이유중에 하나가 된다.

따라서 결국 코드는 아래와 같은 방식이 될 것이다.

library(parallel)

sleep_time <- 10

p <- mcparallel({
    # do some work
    Sys.sleep(sleep_time)
    iris
}, "get_iris", mc.interactive = TRUE)

# 프로세싱이 완료된 결과를 받아온다.
iris_df <- mccollect(p, wait = F, timeout = sleep_time + 1)[[1]]

위 코드에서 문제는 mccollect로 언제 프로세싱 결과물을 받아와야 되는가인데, wait=TRUE로 주면 위와 같은 코드로 잡을 수행하는 의미가 없다는 문제가 있으니 잡이 모두 수행이 되었을 때 뭔가로 알람을 주면 될 것이다.

예전에 필자의 경우 라즈베리 파이로 센서놀이를 할때 센서의 이벤트를 폰으로 받아보려 pushover라는 앱을 구매한 적이 있는데, 이 앱을 통해서 알람을 받으면 될 거란 생각에 관련 패키지를 찾아보니 notifyR이라는 패키지가 pushover로 메시지를 전송하는 기능을 제공하고 있어 간단하게 아래와 같이 구현해 봤다. 물론 5천원 가량되는 pushover앱을 사용하지 않더라도 이 방식으로도 가능하다.

library(notifyR)
library(parallel)

sleep_time <- 10

p <- mcparallel({
    # do some work
    Sys.sleep(sleep_time)
    # 완료후 메시지 전송
    send_push("user_key.....", message = "잡 종료")
    iris
}, "get_iris", mc.interactive = TRUE)

iris_df <- mccollect(p, wait = F)[[1]]

이상으로 R로 데이터 분석 코드를 실행하고 기다리고 있다는게 변명이 될 수 있다는 사실을 만천하게 공유하는 바이다.

CC BY-NC 4.0 꽤 오랜 시간이 걸릴 R 코드를 돌린다면… by from __future__ import dream is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.