병렬 1.29.0: Linux에서 새로운 기술 및 통신 지연 감소

동시에 1.29.0은 CRAN에 있습니다. 평행의 패키지는 강화 병렬 패키지를 – 우리의 내장 R 패키지 병렬 처리 – 기존 기능을 개선하고 새로운 추가. 다소 단순화, 평행 당신이 그렇지 않으면에서 찾을 기대하는 일을 제공하는 병렬 패키지로 제공된다. 미래의 패키지에 의존하는 평행의 로컬 및 원격 병렬화를 위해 내부적으로 패키지.

5개월 전에 병렬로 작성한 이전 게시물 이후 병렬 패키지에는 몇 가지 버그가 수정되었으며 몇 가지 새로운 기능이 추가되었습니다.

  • 새로운 
    isForkedChild ()

     R이 분기된 프로세스에서 실행되는지 테스트하려면,

  • 새로운 
    isNodeAlive ()

     하나 이상의 클러스터 노드 프로세스가 실행 중인지 테스트하려면

  • 사용 가능한 코어 ()

     이제 Bioconductor 설정도 존중합니다.

  • makeClusterPSOCK ( …, rscript = “*” )

     적절한 Rscript 실행 파일로 자동 확장됩니다.

  • makeClusterPSOCK ( …, rscript_envs = c ( UNSET_ME = NA_character_ ))

     클러스터 노드에서 환경 변수 설정을 해제하고

  • makeClusterPSOCK ()

     Unix에서 통신 대기 시간이 짧은 클러스터를 설정합니다.

다음은 이러한 새로운 기능에 대한 자세한 설명입니다.

새로운 함수 isForkedChild()

Unix 및 macOS에서 R을 실행하면 소위 분기 병렬 처리를 사용하여 코드를 병렬화할 수 있습니다 . 이는 코드를 병렬화하는 매우 편리한 방법입니다. 특히 분기가 운영 체제의 핵심에서 구현되고 R 수준에서 작업을 수행하기 위해 수행해야 하는 추가 작업이 거의 없기 때문입니다. 다른 병렬화 솔루션과 비교하여 분기 처리는 종종 오버헤드가 적기 때문에 처리 시간이 단축됩니다. 현재까지 포크를 사용하여 병렬화하는 가장 유명한 방법은 다음과 같습니다.

맥플라이 ()

의 병렬 패키지. 예를 들어,

라이브러리 ( 병렬 )
y < mcapply ( X, some_slow_fcn, mc. 코어 = 4 )

처럼 작동 

랩플라이 ( X, some_slow_fcn )

그러나 4개의 CPU 코어를 사용하여 동일한 작업을 병렬로 수행합니다. MS Windows는 분기 처리를 지원하지 않습니다 . 사용하려는 모든 시도

맥플라이 ()

 자동으로 순차적으로 폴백하게 됩니다. 

()

 전화.

에서 미래의 생태계, 당신은과 병렬화를 포크 얻을

멀티코어

 백엔드, 예

도서관 ( 미래 . 적용 )
계획 ( 멀티코어, 작업자 = 4 )
y < future_lapply ( X, some_slow_fcn )

불행히도 포크를 사용하여 모든 유형의 코드를 병렬화할 수는 없습니다. 완료되면 오류가 발생할 수 있지만 최악의 경우 R 프로세스가 충돌(세그먼트 오류)됩니다. 예를 들어, 일부 그래픽 사용자 인터페이스(GUI)는 분기된 처리(예: RStudio 콘솔)와 잘 작동하지 않지만 다른 GUI도 마찬가지입니다. 다중 스레드 병렬화는 분기된 병렬화 내에서 실행할 때 문제를 일으키는 것으로 보고되었습니다. 분기된 프로세스에서 실행될 경우 소프트웨어 충돌 위험이 있는 코드를 참조하기 위해 포크 안전 코드 와 대조적으로 포크 안전 코드 가 아닌 코드 에 대해 이야기하는 경우가 있습니다.

다음은 R-코어 개발자 Simon Urbanek과 저자입니다. 

맥플라이 ()

2020-04-28에 R-devel 스레드에서 ‘mclapply는 GAM을 실행할 때 MacOS에서 NULL을 반환합니다’ 에 썼습니다.

사용하지 마세요 

맥 병렬 ()

사용자가 설정할 수 있는 기본값이 아닌 옵션을 제외하고 패키지에서 … [위]에 설명됨. Multicore는 컴퓨팅 집약적인 작업을 위해 많은 코어를 사용해야 하는 HPC 응용 프로그램을 위한 것이지만 RStudio와 잘 작동하지 않으며 더 중요한 것은 사용 가능한 리소스를 알지 못하므로 사용자만 언제 사용하는 것이 안전한지 알려줄 수 있습니다. . 멀티 코어 시스템은 종종 공유되므로 감지된 모든 코어를 사용하는 것은 매우 나쁜 생각입니다. 사용자가 명시적으로 활성화할 수 있어야 하지만 기본적으로 활성화되어서는 안 됩니다.

R의 특정 함수 호출이 포크로부터 안전한지 여부가 항상 명확하지는 않습니다. 특히 모든 코드를 직접 작성하지 않은 경우에는 더욱 그렇습니다. 이 때문에 더 많은 시행 착오를 거치므로 작동하는지 확인하십시오. 그러나 특정 함수 호출이 포크로부터 안전 하지 않다는 것을 알고 있을 때 분기 병렬화에서 사용하지 않도록 보호하는 것이 유용합니다. 에 평행하게 (> = 1.28.0), 우리는 기능을 사용할 수 있습니다

isForkedChild ()

R이 분기된 자식 프로세스에서 실행되는지 여부를 테스트합니다. 예를 들어, 저자는

some_slow_fcn ()

 위에서 다음과 같이 실수로부터 보호할 수 있습니다.

some_slow_fcn < 기능 ( x ) {
if ( 병렬:: isForkedChild ()) {
stop ( “이 함수는 *forked* 병렬 처리에서 사용하면 안 됩니다.” )
}
y < non_fork_safe_code ( x )
}

또는 덜 선호되고 포크 안전하지 않은 대안이 있는 경우 분기된 자식 프로세스에서 실행되는 R에 대해 조건부로 실행할 수 있습니다.

some_slow_fcn < 기능 ( x ) {
if ( 병렬:: isForkedChild ()) {
y < fork_safe_code ( x )
} 다른 {
y < 대체 코드 ( x )
}
}

새로운 함수 isNodeAlive()

새로운 기능 

isNodeAlive ()

하나 이상의 노드가 활성 상태인지 확인합니다. 예를 들어,

라이브러리 ( 병렬 )
cl < makeClusterPSOCK ( 3 )
isNodeAlive ( cl )
#> [1] 참 참 참

에뮬레이션할 수 있는 두 번째 병렬 작업자 충돌을 상상해 보십시오.

clusterEvalQ ( cl [ 2 ] , 도구:: pskill ( 시스템 getpid ()))
#> Error in unserialize(node$con) : 연결에서 읽는 동안 오류가 발생했습니다.

그러면 우리는 다음을 얻습니다.

isNodeAlive ( cl )
#> [1] 참 거짓 참

NS 

isNodeAlive ()

 함수는 운영 체제에 쿼리하여 해당 프로세스가 여전히 실행 중인지 확인합니다. 

makeClusterPSOCK ()

시작될 때. 작업자의 PID를 알 수 없는 경우

없음

대신 반환됩니다. 예를 들어, 반대로

병렬로 :: makeClusterPSOCK ()

병렬:: makeCluster ()

 PID를 기록하지 않으며 결과적으로 결측값을 얻습니다.

라이브러리 ( 병렬 )
cl < – 병렬:: makeCluster ( 3 )
isNodeAlive ( cl )
#> [1] NA NA NA

마찬가지로 병렬 작업자 중 하나가 원격 시스템에서 실행되는 경우 PID가 존재하는지 여부에 대해 원격 시스템에 쉽게 쿼리할 수 없습니다. 그런 경우는,

없음

반환됩니다. 아마도 우리는 병렬 의 미래 버전에서 원격 머신도 쿼리할 수 있을 것입니다 . 그러나 지금은 불가능합니다.

availableCores()는 Bioconductor 설정을 존중합니다.

기능 

사용 가능한 코어 ()

하드웨어와 시스템 환경을 쿼리하여 실행될 수 있는 CPU 코어 수를 찾습니다. 최종 사용자, 시스템 관리자, 상위 R 프로세스, 운영 체제, 작업 스케줄러 등이 설정할 수 있는 시스템 설정, 환경 변수 및 R 옵션을 확인하여 이를 수행합니다. 사용할 때

사용 가능한 코어 ()

, 할당된 것보다 더 많은 CPU 리소스를 사용하는 것에 대해 걱정할 필요가 없습니다. 이는 동일한 시스템의 다른 모든 리소스와 함께 원활하게 실행되도록 보장하는 데 도움이 됩니다.

에서 병렬 (> 1.29.0 =),

사용 가능한 코어 ()

이제 Bioconductor별 설정에도 민첩합니다. 예를 들어, BiocParallel 1.27.2는 환경 변수를 도입했습니다.

BIOCPARALLEL_WORKER_NUMBER

병렬화를 위해 BiocParallel 을 사용할 때 병렬 작업자의 기본 수를 설정합니다 . 마찬가지로 Bioconductor 검사 서버에서 환경 변수를 설정합니다.

BBS_HOME

BiocParallel 이 코어 수를 4개로 제한 하는  사용합니다. 지금 

사용 가능한 코어 ()

이러한 설정도 반영하며, 이는 다음 과 같은 미래 설정을 의미합니다.

계획 ( 다중 세션 )

 또한 자동으로 Bioconductor 설정을 존중합니다.

기능 

사용 가능한 작업자 ()

에 의존하는 

사용 가능한 코어 ()

 따라서 폴백으로 이러한 Bioconductor 환경 변수에도 민첩합니다.

makeClusterPSOCK(…, rscript = “*”)

논쟁 

스크립트

 NS 

makeClusterPSOCK ()

 정확히 제어하는 ​​데 사용할 수 있습니다. 

R스크립트

실행 파일은 병렬 작업자를 시작하는 데 사용되며 해당 실행 파일이 시작되는 방법도 있습니다. 기본 설정으로 충분하지만 Linux 컨테이너 내에서 작업자를 시작하려면 다음을 조정하여 수행할 수 있습니다.

스크립트

. 에 대한 도움말 페이지

makeClusterPSOCK ()

이것에 대한 몇 가지 예가 있습니다. 다른 설정에도 사용할 수 있습니다. 예를 들어 원격 Linux 시스템에서 두 개의 병렬 작업자를 시작하여 CPU 우선 순위가 해당 시스템에서 실행 중인 다른 처리보다 낮도록 하려면 (*)를 사용할 수 있습니다.

작업자 < 담당자 ( “remote.example.org” , 시간 = 2 )
cl < makeClusterPSOCK ( 작업자, rscript = c ( “nice” , “Rscript” ))

이로 인해 두 개의 R 작업자가 다음을 사용하여 시작됩니다. 

좋은 Rscript …

. 유닉스 명령

멋진

 만드는 것입니다 

R스크립트

낮은 CPU 우선 순위로 실행합니다. 더 낮은 우선 순위로 실행함으로써 병렬 작업이 해당 시스템에서 실행 중인 다른 소프트웨어에 부정적인 영향을 미칠 위험을 줄입니다. 예를 들어 누군가가 우리 모르게 대화형 작업에 해당 시스템을 사용할 수 있습니다. 다음을 통해 로컬 시스템에서 동일한 작업을 수행할 수 있습니다.

cl < makeClusterPSOCK ( 2L,
rscript = c ( “좋은” , 파일. 경로 ( R. ( “bin” ) , “Rscript” )))

여기에서 절대 경로를 지정했습니다. 

R스크립트

 다른 버전이 아닌 기본 R 세션과 동일한 버전의 R을 실행하는지 확인하기 위해 

R스크립트

 시스템에있을 수 있습니다 

.

병렬로 1.29.0 부터 시작 하여 위의 두 예제에서 Rscript 사양을 다음과 같이 바꿀 수 있습니다.

“*”

, 다음과 같이:

작업자 < 담당자 ( “remote-machine.example.org, 시간 = 2L)
cl <- makeClusterPSOCK(작업자, rscript = c(” 좋은 “, ” *” ))

그리고

cl < makeClusterPSOCK ( 2L, rscript = c ( “좋은” , “*” ))

사용시, 

makeClusterPSOCK ()

 확장됩니다 

“*”

원격 실행 여부에 따라 적절한 Rscript 사양으로 변경합니다. 편의성을 더욱 강조하려면 다음을 고려하십시오.

작업자 < c ( “localhost” , “remote-machine.example.org” )
cl < makeClusterPSOCK ( 작업자, rscript = c ( “nice” , “*” ))

두 개의 병렬 작업자를 시작합니다. 하나는 로컬 시스템에서 실행되고 다른 하나는 원격 시스템에서 실행됩니다.

미래를 사용할 때 전달할 수 있습니다.

스크립트

 에게 

계획 ( 다중 세션 )

 그리고 

계획 ( 클러스터 )

 에서와 같이 동일한 것을 달성하기 위해

계획 ( 클러스터, 작업자 = 작업자, rscript = c ( “nice” , “*” ))

그리고

계획 ( 다중 세션, 작업자 = 2L, rscript = c ( “nice” , “*” ))

(*) 여기서 우리가 사용하는 

멋진

 예를 들어, 방법을 설명하는 간단한 방법이기 때문에 

스크립트

사용할 수 있습니다. 사실 이미 논란이 되고 있는 

르니스

, 우리는 사용하지 않고 동일한 것을 달성하기 위해 사용할 수 있습니다 

스크립트

 논쟁.

makeClusterPSOCK(…, rscript_envs = c(UNSET_ME = NA_character_))

논쟁 

rscript_envs

 NS 

makeClusterPSOCK ()

클러스터 노드에서 환경 변수를 설정하거나 기본 R 세션에서 클러스터 노드로 기존 변수를 복사하는 데 사용할 수 있습니다. 예를 들어,

cl < makeClusterPSOCK ( 2 , rscript_envs = c ( PI = “3.14” , “MY_EMAIL” ))

시작하는 동안 환경 변수를 설정합니다. 

파이

 두 클러스터 노드 각각에서 

3. 14

. 그것은 또한 설정됩니다

내 이메일

 그들에 대한 가치 

시스템 getenv ( “MY_EMAIL” )

 현재 R 세션에서

병렬 1.29.0 부터 이제 환경 변수가 클러스터 노드에 설정된 경우 환경 변수 도 설정 해제 할 수 있습니다 . 값이 누락된 명명된 요소는 해당 환경 변수가 설정 해제되도록 합니다. 예를 들어

cl < makeClusterPSOCK ( 2 , rscript_envs = c ( _R_CHECK_LENGTH_1_CONDITION_ = NA_character_ ))

그 결과 합격 

-e ‘Sys.unsetenv(“_R_CHECK_LENGTH_1_CONDITION_”)’

 에게 

R스크립트

 각 작업자를 시작할 때.

makeClusterPSOCK()는 Unix에서 통신 대기 시간이 짧은 클러스터를 설정합니다.

Unix의 R 에서는 병렬 작업자와 기본 R 세션 (**) 간의 통신에 상당한 대기 시간 이 있는 것으로 나타났습니다 . R (> = 4.1.0)에서 시작, 전용 R 옵션을 설정하여 대기 시간을 줄일 수있다 노동자의 각 예를 들면,

rscript_args < c ( “-e” , shQuote ( “options(socketOptions = ‘지연 없음’)” )
cl < – 병렬:: makeCluster ( 작업자, rscript_args = rscript_args ))

이것은 매우 장황하므로 이것을 병렬로 새 기본값으로 만들었습니다 (>= 1.29.0). 즉, 다음을 계속 사용할 수 있습니다.

cl < – 병렬로:: makeClusterPSOCK ( 작업자 )

위의 혜택을 누리기 위해. 도움말 보기

makeClusterPSOCK ()

 이 새 기본값을 변경하는 방법에 대한 옵션은

다음은 새 설정이 있는 경우와 없는 경우의 지연 시간 차이를 보여주는 예입니다.

cl_parallel < – 병렬:: makeCluster ( 1 )
cl_parallelly < – 병렬로:: makeClusterPSOCK ( 1 )
res < – bench:: mark ( 반복 = 1000L,
병렬 = 병렬:: clusterEvalQ ( cl_parallel, iris ) ,
병렬 = 병렬:: clusterEvalQ ( cl_parallelly, iris )
)
해상도 [ , c ( 1 : 4 , 9 )]
#> # 티블: 2 × 5
#> 표현식 최소 중앙값 `itr/sec` total_time
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:tm>
#> 1 병렬 277µs 44ms 22.5 44.4s
#> 2 병렬로 380µs 582µs 1670. 598.3ms

이를 통해 1,000개의 병렬 작업에 대한 총 대기 시간 오버헤드가 44초에서 0.60초로 감소했음을 알 수 있습니다. 이는 평균 75배 미만입니다. 이것은 병렬 코드가 더 빨리 실행된다는 것을 의미합니까? 아니요, 통신 대기 시간 이 감소했을 뿐입니다 . 하지만 결과 를 기다리 느라 시간을 낭비 할 필요가 없는데 왜 시간을 낭비 합니까? 이것이 내가 기본값을 병렬로 변경한 이유 입니다. 또한 MS Windows 및 macOS와 동등한 Unix 환경을 제공합니다.

상대적으로 높은 대기 시간은 Unix에만 영향을 미칩니다. MS Windows 및 macOS는 이러한 추가 대기 시간을 겪지 않습니다. 예를 들어 위와 동일한 Linux 컴퓨터의 가상 머신에서 실행되는 MS Windows 10에서는 다음을 얻습니다.

#> # 티블: 2 × 5
#> 표현식 최소 중앙값 `itr/sec` total_time
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:tm>
#> 1 병렬 191us 314us 2993. 333ms
#> 2 병렬 164us 311us 3227. 310ms

미래를 함께 사용하는 경우

계획 ( 다중 세션 )

 또는 

계획 ( 클러스터 )

에 의존하기 때문에 이미 성능 향상의 이점을 누리고 있습니다. 

병렬로 :: makeClusterPSOCK ()

 내부적으로.

(**) 기술적 세부 사항 : 옵션

소켓 옵션

 인수의 기본값을 설정합니다. 

옵션

 NS 

베이스:: socketConnection ()

. 기본값은

없는

, 그러나 우리가 그것을 설정하면 

“지체없이”

, 생성된 TCP 소켓 연결은 

TCP_NODELAY

깃발. 사용할 때

TCP_NODELAY

, TCP 연결은 더 이상 소위 Nagle 알고리즘을 사용하지 않습니다. 그렇지 않으면 TCP가 패킷을 보내기 전에 각 패킷을 채우도록 하여 네트워크를 통해 보내야 하는 TCP 패킷 수를 줄이는 데 사용됩니다. 새로운 것을 사용할 때 

“지체없이”

, 이 버퍼링은 비활성화되고 데이터가 들어오는 즉시 패킷이 전송됩니다. 이 개선에 대한 크레딧 은 문제를 식별하고 R-devel에 보고 한 Jeff Keller, 투구한 Iñaki Úcar 및 Simon Urbanek에게 돌아가야 합니다. 구현된 지원

socketConnection ( …, 옵션 = “지연 없음” )

 R 4.1.0의 경우.

버그 수정

마지막으로 병렬 1.26.0 이후 가장 중요한 버그 수정 사항 은 다음과 같습니다.

  • 사용 가능한 코어 ()

     없는 Linux 시스템에서 오류를 생성합니다. 

    nproc

     설치되었습니다.

  • makeClusterPSOCK ()

     환경 변수인 경우 “freePort(port) 오류: ‘port’ 인수의 알 수 없는 값: ‘auto'”로 실패했습니다. 

    R_PARALLEL_PORT

     포트 번호로 설정되었습니다.

  • 지원하지 않는 R 환경에서 
    setup_strategy = “병렬”

    makeClusterPSOCK ()

     로 돌아가지 못했습니다. 

    setup_strategy = “순차적”

    .

다른 모든 버그 수정 및 업데이트는 NEWS 를 참조하십시오 .

오버앤아웃!

Leave a Comment