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 <- 10
_を設定し、return(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
_
@Tensibaiは正しいです。 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つの関数は現在の環境に含まれていないため、doParallel
はRの新しいインスタンスを起動するときにそれらを無視しますが、parse_voice_block
は現在のスコープ内にあるため、どこにあるかがわかります。さらに、Rの新しいインスタンスごとにどのパッケージをロードするかを指定する必要があります。Tensibaiが述べたように、これはプロセスを分岐して実行しているのではなく、Rの複数のインスタンスを起動してコマンドを同時に実行しているためです。
doParallel
を使用して登録すると、次のように不幸になります。
_registerDoParallel(2)
_
次に、doParallel
はLinuxおよびMac OS Xではmclapply
を使用しますが、Windowsでは暗黙的に作成されたクラスターオブジェクトでclusterApplyLB
を使用します。これにより、Linuxではコードが機能しますが、Windowsでは失敗します。これは、mclapply
が原因で、fork
を使用するとワーカーがマスターのクローンになるためです。そのため、通常は次のコードを使用してコードをテストします。
_cl <- makePSOCKcluster(2)
registerDoParallel(cl)
_
必要なすべてのパッケージをロードし、必要なすべての関数と変数をエクスポートしていることを確認してから、registerDoParallel(2)
に切り替えて、それをサポートするプラットフォームでmclapply
の利点を取得します。
doParallel
がmclapply
を使用する場合、_.packages
_および_.export
_オプションは無視されますが、移植性のために常に使用することをお勧めします。
Foreachの自動エクスポート機能は、関数内で使用するとスムーズに機能しません。これは、foreachは、自動エクスポートする内容について保守的であるためです。現在の環境で定義されている変数と関数を自動エクスポートすることはかなり安全に思えますが、Rのスコープルールは複雑であるため、それ以外では危険だと思われます。
あなたの2つの回避策は、活発に開発されているパッケージに対してあまり安定していないというあなたのコメントに同意する傾向がありますが、f
とg
がパッケージfoo
で定義されている場合、次に、foreach _.package
_オプションを使用して、パッケージfoo
をワーカーにロードする必要があります。
_g <- function(){
r = foreach(x = 1:4, .packages='foo') %dopar% {
return(x + f())
}
return(r)
}
_
その場合、f
は、foreachによって暗黙的または明示的にエクスポートされていなくても、g
のスコープ内になります。ただし、これには、ワーカーが実行するコードがf
で定義されていないため、foo
が(内部関数ではなく)foo
のエクスポート関数である必要があります。なので、エクスポートされた関数にのみアクセスできます。 (「エクスポート」という用語を2つの異なる方法で使用して申し訳ありませんが、回避するのは困難です。)
自動エクスポートルールを調整する必要があるかどうか常に疑問に思っているので、私はいつもあなたのようなコメントを聞くのに興味があります。この場合、パッケージで定義されている関数によってforeachループが実行された場合、クラスターワーカーは_.packages
_オプションを必要とせずにそのパッケージを自動ロードする必要があると考えています。私はそれを調べて、おそらくこれをdoParallel
とdoSNOW
の次のリリースに追加します。