【问题标题】:Why do pdf files that are printed using R's foreach() %dopar% construct turn out corrupted and unreadable?为什么使用 R\'s foreach() %dopar% 构造打印的 pdf 文件会损坏且不可读?
【发布时间】:2022-09-24 13:37:54
【问题描述】:

我在下面有一个最小的可重现示例脚本,它将相同的图写入两个 pdf 文件,首先使用标准 for 循环串行,然后并行使用 R\'s foreach() %dopar% 构造:

library(ggplot2)
library(parallel)
library(doParallel)
library(foreach)

# Print an arbitrary dummy plot (from the standard \"cars\" data set) to a
# specific integer graphical device number.
makeplot <- function(graph_dev) {
  dev.set(graph_dev)
  plt <- ggplot(cars) + geom_point(aes(x=speed, y=dist))
  # Print the same plot repeatedly 10 times, on 10 sequential pages, in
  # order to purposefully bloat up the file size a bit and convince
  # ourselves that actual plot content is really being saved to the file.
  for(ii in seq(10)) {print(plt)}
}

# A pair of pdf files that we will write serially, on a single processor
fser <- c(\'test_serial_one.pdf\', \'test_serial_two.pdf\')

# A pair of pdf files that we will write in parallel, on two processors
fpar <- c(\'test_parallel_one.pdf\', \'test_parallel_two.pdf\')

# Open all four pdf files, and generate a key-value pair assigning each
# file name to an integer graphical device number
fnmap <- list()
for(f in c(fser, fpar)) {
  pdf(f)
  fnmap[[f]] <- dev.cur()
}

# Loop over the first two pdf files using a basic serial \"for\" loop
for(f in fser) {makeplot(fnmap[[f]])}

# Do the same identical loop content as above, but this time using R\'s
# parallelization framework, and writing to the second pair of pdf files
registerDoParallel(cl=makeCluster(2, type=\'FORK\'))
foreach(f=fpar) %dopar% {makeplot(fnmap[[f]])}

# Close all four of the pdf files
for(f in names(fnmap)) {
    dev.off(fnmap[[f]])
}

前两个输出文件test_serial_one.pdftest_serial_two.pdf 的最终文件大小均为 38660 字节,可以使用标准 pdf 阅读器(如 Adob​​e Acrobat Reader 或类似阅读器)正确打开和显示。

后两个输出文件 test_parallel_one.pdftest_parallel_two.pdf 的最终文件大小均为 34745 字节,但在尝试使用标准工具读取时会返回文件损坏错误:例如,\"打开此文档时出错。无法打开此文件,因为它没有页面。\"

串行与并行版本的文件大小大致相等的事实向我表明,来自 pdf 阅读器的错误消息可能不正确:并行循环实际上就像在串行循环中一样成功地将页面内容转储到文件中, 而是可能在并行化输出文件的页面内容末尾缺少某种文件页脚信息,可能是因为这两个文件没有成功关闭。

出于各种技术原因,我希望能够在 foreach() %dopar% 构造之外打开和关闭多个 pdf 文件,同时在并行循环内部使用 dev.set() 来选择在每次循环迭代中写入哪个文件。

本例中并行循环中发生的文件损坏的根本原因是什么?以及如何更正它:即,如何修改我的代码以正确关闭文件并在并行循环完成后附加必要的 pdf 文件页脚信息?

  • 你能提供输出文件吗?
  • @johnwhitington:我不确定该怎么做,因为它们是 pdf 文件,我认为我无法将其嵌入到我的问题中。但是,如果您运行我包含的代码 sn-p,它应该会在您自己的系统上本地为您生成相同的输出文件。
  • 经常并行尝试 pdf 失败的风险很高,线程和资源需要重复,因为为一个 pdf 编写器锁定字体文件会阻止它在总线上为另一个线程传输,将其乘以许多资源,例如 gpu 和线程安全是比串行慢,通常运行多个 gpu 线程需要并行计算机,例如图形农场,其中 100 个文件发送到 100 个 CPU 或一次 10 个串行发送到 10 个 CPU在某些情况下差异很大,但时间增益通常很差

标签: r pdf doparallel parallel-foreach


【解决方案1】:

尽管分配了不同的文件,但分叉的进程共享一些图形设备管道。使用 MPI 后端,或将代码编写为 HPC 集群的 SPMD,将为您提供与排名一样多的 R 会话(和图形管道)。

【讨论】:

    猜你喜欢
    • 2012-05-07
    • 1970-01-01
    • 1970-01-01
    • 2011-07-29
    • 1970-01-01
    • 2020-01-17
    • 1970-01-01
    • 2010-10-31
    • 1970-01-01
    相关资源
    最近更新 更多