簡體   English   中英

R中的並行遞歸function?

[英]Parallel recursive function in R?

我整個星期都在為這個問題絞盡腦汁,並且真的可以使用外部視角。 基本上我已經構建了一個遞歸樹 function ,其中一層中每個節點的 output 用作后續層中節點的輸入。 我在這里生成了一個玩具示例,其中每個調用都會生成一個大矩陣,將其拆分為子矩陣,然后將這些子矩陣傳遞給后續調用。 與 Stack 上類似問題的主要區別在於,每次調用tree_search實際上並不返回任何內容,它只是將結果附加到 CSV 文件中。

現在我想並行化這個 function。 但是,當我使用mclapplymc.cores=2運行它時,運行時間會增加! 當我在帶有mc.cores=12的多核集群上運行它時,也會發生同樣的情況。 這里發生了什么? 父節點是否在等待子節點返回一些output? 這與 fork/socket 並行化有關嗎?

作為背景,這是模擬白細胞中基因激活以響應病毒感染的算法的一部分。 我是一名生物學家和自學成才的程序員,所以我在這里有點超出我的深度 - 任何幫助或線索將不勝感激!

# Load libraries.
library(data.table)
library(parallel)

# Recursive tree search function.
tree_search <- function(submx = NA, loop = 0) {

  # Terminate on fifth loop.
  message(paste("Started loop", loop))
  if(loop == 5) {return(TRUE)}

  # Create large matrix and do some operation.
  bigmx <- matrix(rnorm(10), 50000, 250)
  bigmx <- sin(bigmx^2)

  # Aggregate matrix and save output.
  agg <- colMeans(bigmx)
  append <- file.exists("output.csv")
  fwrite(t(agg), file = "output.csv", append = append, row.names = F)

  # Split matrix in submatrices with 100 columns each.
  ind <- ceiling(seq_along(1:ncol(bigmx)) / 100)

  lapply(unique(ind), function(i) {

    submx <- bigmx[, ind == i]

    # Pass each submatrix to subsequent call.
    loop <- loop + 1
    tree_search(submx, loop) # sub matrix is used to generate big matrix in subsequent call (not shown)

  })

}

# Initiate tree search.
tree_search()

經過更多的腦筋急轉彎和實驗,我最終回答了我自己的問題。 我不打算參考原始示例,因為我已經改變了很多方法。 相反,我將分享一些可能對處於類似情況的人有所幫助的一般性觀察。

1.) For循環比lapply和遞歸函數更有效

使用 lapply 時,每次調用都會創建當前環境的副本。 這就是為什么你可以這樣做:

x <- 5
lapply(1:10, function(i) {
   x <- x + 1
   x == 6 # TRUE
})
x == 5 # ALSO TRUE

最后 x 仍然是 5,這意味着每次調用lapply都在操作 x 的單獨副本。 如果 x 實際上是一個帶有 10,000 個變量的大型 dataframe,那就不好了。 另一方面, for循環允許您覆蓋每個循環上的變量。

x <- 5
for(i in 1:10) {x <- x + 1}
x == 5 # FALSE

2.) 並行化一次

將任務分配到不同的節點需要大量的計算開銷,並且可以抵消您從並行化腳本中獲得的任何收益。 因此,您應該謹慎使用mclapply 就我而言,這意味着不要將mclapply放在遞歸的 function 中,它會被調用數十到數百次。 相反,我將起點分成 16 個部分,並在不同的節點上運行 16 次不同的樹搜索。

3.) 您可以使用mclapply來限制 memory 的使用

如果您將作業分成 10 個部分並使用mclapplymc.preschedule=F處理它們,則每個核心一次只能處理 10% 的作業。 例如,如果mc.cores設置為兩個,那么其他 8 個“節點”將等到一個部分完成后再開始一個新的部分。 如果您遇到 memory 問題並希望防止每個循環超出其處理能力,這將非常有用。

最后說明

這是迄今為止我研究過的更有趣的問題之一。 但是,遞歸樹函數很復雜。 畫出算法,強迫自己花幾天時間遠離你的代碼,這樣你就能以全新的視角回來。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM