18

foreach には、理解できない問題があります。次のコードは、私が試した 2 台の Windows コンピューターでは失敗しますが、同じバージョンの R と doParallel を実行している 3 台の Linux コンピューターでは成功します。

library("doParallel")
registerDoParallel(cl=2,cores=2)

f <- function(){return(10)}
g <- function(){
    r = foreach(x = 1:4) %dopar% {
        return(x + f())
    }
    return(r)
}
g()

これら 2 台の Windows コンピューターでは、次のエラーが返されます。

Error in { : task 1 failed - "could not find function "f""

ただし、これは Linux コンピューターで問題なく動作し、%dopar% の代わりに %do% を使用しても問題なく動作し、通常の for ループでも問題なく動作します。

同じことが変数にも当てはまりますi <- 10return(x + f())return(x + i)

同じ問題を抱えている他の人には、次の 2 つの回避策があります。

1) .export を使用して、必要な関数と変数を明示的にインポートします。

r = foreach(x=1:4, .export="f") %dopar% 

2) すべてのグローバル オブジェクトをインポートします。

r = foreach(x=1:4, .export=ls(.GlobalEnv)) %dopar% 

これらの回避策の問題は、大規模で活発に開発中のパッケージに対して最も安定していないことです。いずれにせよ、foreach は for のように動作するはずです。

これを引き起こしている原因と、修正があるかどうかについてのアイデアはありますか?


機能が動作するコンピュータのバージョン情報:

R version 3.2.2 (2015-08-14)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: CentOS release 6.5 (Final)

other attached packages:
[1] doParallel_1.0.10 iterators_1.0.8   foreach_1.4.3

機能が動作しないコンピュータ:

R version 3.2.2 (2015-08-14)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

other attached packages:
[1] doParallel_1.0.10 iterators_1.0.8   foreach_1.4.3  
4

2 に答える 2

12

@テンシバイは正しいです。Windows で使用しようとするとdoParallel、現在のスコープにない、使用したい関数を「エクスポート」する必要があります。私の経験では、この作業を行う方法は、次の (編集された) 例です。

format_number <- function(data) {
  # do stuff that requires stringr
}

format_date_time <- function(data) {
  # do stuff that requires stringr
}

add_direction_data <- function(data) {
  # do stuff that requires dplyr
}

parse_data <- function(data) {
  voice_start <- # vector of values
  voice_end <- # vector of values
  target_phone_numbers <- # vector of values
  parse_voice_block <- function(block_start, block_end, number) {
    # do stuff
  }

  number_of_cores <- parallel::detectCores() - 1
  clusters <- parallel::makeCluster(number_of_cores)
  doParallel::registerDoParallel(clusters)
  data_list <- foreach(i = 1:length(voice_start), .combine=list,
                       .multicombine=TRUE, 
                       .export = c("format_number", "format_date_time", "add_direction_data"), 
                       .packages = c("dplyr", "stringr")) %dopar% 
                       parse_voice_block(voice_start[i], voice_end[i], target_phone_numbers[i])
  doParallel::stopCluster(clusters)
  output <- plyr::rbind.fill(data_list)
}

最初の 3 つの関数は現在の環境に含まれていないため、doParallelR の新しいインスタンスを起動するときにそれらを無視しますがparse_voice_block、現在のスコープ内にあるため、どこを見つけるべきかがわかります。さらに、R の新しいインスタンスごとにどのパッケージをロードする必要があるかを指定する必要があります。Tensibai が述べたように、これは、プロセスをフォークして実行するのではなく、R の複数のインスタンスを起動してコマンドを同時に実行するためです。

于 2016-01-07T14:26:29.433 に答える