正如你已經想通了,clusterExport
會在.GlobalEnv
指定變量,除非與envir
參數設置爲其它。但在您的特定示例中,iih_data
正在與您正在執行的未命名函數一起被序列化,因此您將通過clusterExport
不會實際使用您要通過clusterExport
導出到工作人員的副本。事實上,執行parCapply
之前在f1
中定義的所有局部變量將與未命名的輔助函數一起序列化併發送給每個工作人員。
這種技術可以使用clusterApply
和clusterApplyLB
時是將數據發送到工人(它實際上由clusterExport
使用本身)非常有用,但你必須知道你在做什麼,否則就顯著傷害你的表現,尤其是,因爲他們不執行parLapply
和parCapply
完成的相同的預先計劃。
這裏有一個簡單的例子,說明了這一點:
library(parallel)
cl <- makePSOCKcluster(3)
f1 <- function() {
iih_data <- 'foo'
parLapply(cl, 1:3, function(i) iih_data)
}
f1()
你可能會認爲,你會得到一個錯誤說「對象‘iih_data’未找到」因爲你還沒有明確的出口,但你別。奇怪的是,當從全局環境中定義函數時,這並不會發生,因爲全局環境從未與函數一起序列化。
如果您認爲這很奇怪,那麼在處理參數時就會變得陌生。考慮下面這個例子:
library(parallel)
cl <- makePSOCKcluster(3)
f1 <- function(iih_data) {
parLapply(cl, 1:3, function(i) iih_data)
}
x <- 'foo'
f1(x)
由於我前面的例子,你可能會認爲這會工作,而是你得到以下錯誤:
Error in checkForRemoteErrors(val) :
3 nodes produced errors; first error: object 'x' not found
但爲什麼它說「對象‘X’不找到「而不是」對象'iih_data'找不到「?這是由於R對函數參數的懶惰評估。該函數及其相關環境將被序列化併發送給工作人員,而無需評估參數「iih_data」。只有在工作人員執行未命名的工作人員功能之前,纔會對其進行評估,這就是當它發現在工作人員的全球環境中未定義「x」時。如果不是調用force
你執行clusterExport(cl, 'iih_data', envir=environment())
f1 <- function(iih_data) {
force(iih_data)
parLapply(cl, 1:3, function(i) iih_data)
}
,它的工作,但不是因爲你已經將它導出到工人:
你可以通過改變f1
來解決這個問題。這是有效的,因爲這個論點是被迫的,但是效率低得多,而且複製到工人全球環境中的價值依然不會被使用。工作者函數仍然會使用通過調用f1
創建的本地環境中的「iih_data」的副本,該副本與未命名的輔助函數一起被序列化。
這可能看起來像是一個學術問題,但一旦您開始從函數內部調用並行函數(如parLapply
和clusterApply
)以執行未命名的工作函數,它就會以各種形式出現。我被這種問題困擾過很多次。
哇,多麼好的和徹底的答案!謝謝!我知道一些複雜的事情正在發生。 – bdeonovic
@Benjamin我包括關於未評估的函數參數的東西,因爲這是一個問題,你遇到了上一個問題,可能被錯誤地標記爲重複。道德是:「小心並行執行關閉」。 –