【问题标题】:Parallelize and speed up R code to read in many files并行化和加速 R 代码以读取许多文件
【发布时间】:2026-02-10 08:25:01
【问题描述】:

我的代码非常适合我的目的(它读取一些具有特定模式的文件,读取每个文件中的矩阵并使用每个文件对计算一些东西......最终输出是一个具有相同大小的矩阵文件编号),看起来像这样:

m<- 100
output<- matrix(0, m, m)

lista<- list.files(pattern = "q")
listan<- as.matrix(lista)
n <- nrow(listan)

for (i in 1:n) {    
AA    <- read.table((listan[i,]), header = FALSE)
A<- as.matrix(AA)
dVarX <- sqrt(mean(A * A))

 for (j in i:n) {
    BB <- read.table ((listan[j,]), header = FALSE)
    B<- as.matrix(BB)
    V <- sqrt (dVarX * (sqrt(mean(B * B))))
    output[i,j] <- (sqrt(mean(A * B))) / V        
 }
}

我的问题是它需要很多时间(我有大约 5000 个矩阵,这意味着 5000x5000 个循环)。 我想并行化,但我需要一些帮助! 期待您的好意建议!

提前谢谢你!

加布

【问题讨论】:

  • 触摸磁盘很慢。想想你从磁盘中读取每个矩阵的次数。为什么不每个矩阵只做一次?
  • 要添加到@joran 的评论中,?read.table内存使用 部分明确表示,“使用 scan 代替矩阵。”
  • ...这只是从磁盘部分读取。您还为每个矩阵复制了 sqrt(mean(B*B)) 的计算。并行化这种低效的代码就像试图通过从家跑到汽车而不是步行来加快通勤速度。
  • @joran 你说得对!!..但我在使用 R (圣诞节前开始!)和编程方面非常新……这就是我需要很多帮助的原因!无论如何,我写了一个命令,只能在创建一个列表时从磁盘读取每个矩阵......但这个列表对于我由 5000 个矩阵组成的 RAM(12GB)来说太大了。该命令是用 llply 完成的。

标签: r performance file-io parallel-processing


【解决方案1】:

瓶颈可能是从磁盘读取。不能保证并行运行代码会使事情变得更快。在这种情况下,多个进程同时尝试从同一个磁盘读取可能比单个进程还要慢。

由于您的矩阵是由另一个 R 进程编写的,因此您确实应该将它们保存为 R 的二进制格式。您正在读取每个矩阵一次且仅一次,因此使您的程序更快的唯一方法是更快地从磁盘读取。

这里有一个例子可以告诉你它可以多快:

# make some random data and write it to disk
set.seed(21)
for(i in 0:9) {
  m <- matrix(runif(700*700), 700, 700)
  f <- paste0("f",i)
  write(m, f, 700)              # text format
  saveRDS(m, paste0(f,".rds"))  # binary format
}

# initialize two output objects
m <- 10
o1 <- o2 <- matrix(NA, m, m)

# get list of file names
files <- list.files(pattern="^f[[:digit:]]+$")
n <- length(files)

首先,让我们使用scan 运行您的代码,这已经比使用read.table 的当前解决方案快很多。

system.time({
  for (i in 1:n) {    
    A <- scan(files[i],quiet=TRUE)

    for (j in i:n) {
      B <- scan(files[j],quiet=TRUE)
      o1[i,j] <- sqrt(mean(A*B)) / sqrt(sqrt(mean(A*A)) * sqrt(mean(B*B)))
    }
  }
})
#    user  system elapsed 
#   31.37    0.78   32.58

现在,让我们使用以 R 的二进制格式保存的文件重新运行该代码:

system.time({
  for (i in 1:n) {    
    fA <- paste0(files[i],".rds")
    A <- readRDS(fA)

    for (j in i:n) {
      fB <- paste0(files[j],".rds")
      B <- readRDS(fB)
      o2[i,j] <- sqrt(mean(A*B)) / sqrt(sqrt(mean(A*A)) * sqrt(mean(B*B)))
    }
  }
})
#    user  system elapsed 
#    2.42    0.39    2.92

所以二进制格式要快 10 倍!并且输出是一样的:

all.equal(o1,o2)
# [1] TRUE

【讨论】:

  • 非常感谢您提供代码和所有清晰有用的解释。真的很感激!!