2017-03-02 10 views
0

%dopar%並列環境内で複数レベルのdo.callをそれぞれネストしています私の外部環境からの関数は、最も内側の関数では見つけることができません。私はの.exportパラメータについて知っていますが、それを使用していますが、何らかの形で名前付きファンクションがチェーン全体に伝播していません。foreach%dopar%環境内でネストされたdo.callが.exportで渡された関数を見つけることができません

私はこの問題は発生しません、次のテストケースに私の問題を軽減:

library(doParallel) 
cl <- makeCluster(4) 
registerDoParallel(cl) 

simple.func <- function(a, b) { 
    return(a+b) 
} 

inner.func <- function(a, b) { 
    return(do.call(simple.func, list(a=a, b=b))) 
} 

outer.func <- function(a, b, my.func=inner.func) { 
    return(do.call(my.func, list(a=a, b=b))) 
} 

main.func <- function(my.list=1:10, my.func=outer.func, 
         my.args=list(my.func=inner.func)) { 
    results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE, 
        .export="simple.func") %dopar% { 
    return(do.call(my.func, c(list(a=i, b=i+1), my.args))) 
    } 
    return(results) 
} 

よりもむしろ正しい答え(一部番号のリスト)を与え、私が手:

Error in { : task 1 failed - "object 'simple.func' not found" 

outer.funcがであっても、if (!exists("simple.func")) stop("Could not find parse.data in scope main.func")をそれぞれの関数の先頭に追加すると(スコープの名前を適切に変更すると)が表示されません。それを見てください。

また、パラメータから使用するのではなく、次のレベルの関数がハードコードされているmain.funcまたはouter.funcの2つのバリエーションをテストしました。これらのバリエーションの両方はです(例えば、期待される結果を出す)が、実際のケースでは、サブ関数をパラメータとして取ることの一般性を保持したいと思います。

# Variation number one: Replace main.func() with this version 
main.func <- function(my.list=1:10, my.func=outer.func, 
         my.args=list(my.func=inner.func)) { 
    results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE, 
        .export=c("simple.func", "outer.func", "inner.func")) %dopar% { 
    return(do.call(outer.func, list(a=i, b=i+1, my.func=inner.func))) 
    } 
    return(results) 
} 

# Variation number two: Replace outer.func() and main.func() with these versions 
outer.func <- function(a, b, my.func=inner.func) { 
    return(do.call(inner.func, list(a=a, b=b))) 
} 

main.func <- function(my.list=1:10, my.func=outer.func, 
         my.args=list(my.func=inner.func)) { 
    results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE, 
        .export=c("simple.func", "inner.func")) %dopar% { 
    return(do.call(my.func, c(list(a=i, b=i+1), my.args))) 
    } 
    return(results) 
} 

私はまた、追加のパラメータとして、それを含めることによって、手動でチェーンダウンsimple.funcを渡すことができますが、これは余分な乱雑に見える、とsimple.funcはちょうど環境の一部として渡されなければならない時に、なぜそれが必要になるでしょうか?

# Variation number three: Replace inner.func(), outer.func(), and main.func() 
# with these versions 
inner.func <- function(a, b, innermost.func=simple.func) { 
    return(do.call(innermost.func, list(a=a, b=b))) 
} 

outer.func <- function(a, b, my.func=inner.func, 
         innermost.args=list(innermost.func=simple.func)) { 
    return(do.call(my.func, c(list(a=a, b=b), innermost.args))) 
} 

main.func <- function(my.list=1:10, my.func=outer.func, 
         my.args=list(my.func=inner.func, 
         innermost.args=list(innermost.func=simple.func))) { 
    results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE, 
        .export="simple.func") %dopar% { 
    return(do.call(my.func, c(list(a=i, b=i+1), my.args))) 
    } 
    return(results) 
} 

誰もが、この問題の根本的な原因ではないかと思われますか? doParallelについては

+0

あなたのコードはそれらのコードでいっぱいです:すべての 'return'呼び出しは不要です。 Rは関数内の最後の式の値を自動的に返します。関数を途中で残すには 'return'が必要です。 –

答えて

0

、および現在のプロセスをforkしない他のdoNnnアダプター、私はがそれを行うだろうハック次を考える:また

main.func <- function(my.list = 1:10, my.func=outer.func, 
         my.args = list(my.func=inner.func)) { 
    results <- foreach(i = my.list, .multicombine = TRUE, .inorder = FALSE, 
        .export="simple.func") %dopar% { 
    environment(my.args$my.func) <- environment() ## <= HACK 
    return(do.call(my.func, args = c(list(a=i, b=i+1), my.args))) 
    } 
    return(results) 
} 

、あなたはdoFutureアダプター(I」を使用することができます私の著者)。次に、グローバルオブジェクトが自動的に識別され、エクスポートされるため、グローバルオブジェクトについて心配する必要はありません。すなわち、.export(または.packages)を指定する必要はありません。たとえば、次のような作品あなたのケースで:

library("doFuture") 
registerDoFuture() 
plan(multisession, workers = 4) 

main.func <- function(my.list = 1:10, my.func = outer.func, 
         my.args = list(my.func = inner.func)) { 
    foreach(i = my.list, .multicombine = TRUE, .inorder = FALSE) %dopar% { 
    do.call(my.func, args = c(list(a = i, b = i+1), my.args)) 
    } 
} 

res <- main.func(1:3) 
str(res) 
## List of 10 
## $ : num 3 
## $ : num 5 
## $ : num 7 

また、すべてに沿ってforeach()をスキップして行うことができます。

library("future") 
plan(multisession, workers = 4) 

main <- function(my.list = 1:10, my.func = outer.func, 
       my.args = list(my.func = inner.func)) { 
    future_lapply(my.list, FUN = function(i) { 
    do.call(my.func, args = c(list(a = i, b = i+1), my.args)) 
    }) 
} 

PS。多くの異なるplan()バックエンドがあります。カバーされていない唯一のものはdoRedisです。

+0

環境()のハックが機能しているようですが、doFutureライブラリを使用すると、クラスタを読み込むためにplan(cluster、workers = cl)を実行しているときに次のようなエラーが発生することがあります: "UseMethod(" tweak ")のエラー: class "function" "のオブジェクトに適用される"微調整 "のためのものです。 これには簡単な答えがありますか、新しい質問を開く(またはあなたのGitHubにバグを提出する)べきですか? – Randall

+0

ええと...別の 'cluster'関数を定義する別のパッケージを添付している可能性はありますか? 'str(cluster)'がそれに属しているとは何か? '' plan( "cluster"、workers = cl) ''や '' plan(future :: cluster、workers = cl) ''がそれを修正していますか?そうでない場合は、https://github.com/HenrikBengtsson/futureに問題を作成して、何が起きているのか把握してください。私に知らせるThxs。 – HenrikB

関連する問題