首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >允许(或规避)对文件的并行写入访问

允许(或规避)对文件的并行写入访问
EN

Stack Overflow用户
提问于 2014-05-07 23:42:50
回答 1查看 450关注 0票数 2

我从多个并行R进程调用一个Windows可执行文件(通过parSapply中的一个parSapply调用)。这个.exe (让我们称之为my.exe)作为参数传递一个文件名,并处理这个文件(细节可能无关紧要)。不幸的是,my.exe在运行时创建了一个日志文件(在与my.exe相同的目录中),并且由于日志文件的名称是固定的,调用my.exe的后续R进程会导致my.exe`抛出错误:

代码语言:javascript
复制
Cannot create result file "log.res". 
Do you have write access in the current directory?

我通过创建my.exe的多个副本(与cluster中的核心数一样多,即7)来解决这个问题。然后,我可以通过向核心传递一个.bat文件的7条路径的向量,确保每个R进程在任何时候都只被一个R进程使用,每个路径都重复调用给定的my.exe副本。

是否有一种更优雅的方法来处理这个问题,也许可以让流程自动创建my.exe的虚拟实例?我不需要日志文件。

,因为这是程序抛出的错误,而不是R抛出的错误,因此我怀疑不可能允许从事务的R端对日志文件进行并发写访问。

理想情况下,我想做这样的事情:

代码语言:javascript
复制
ff <- c('a', 'long', 'vector', 'of', 'file', 'paths') # abbreviated
parSapply(cl, ff, function(f) system(sprintf("my.exe %s", f)))

但是,我转而(或多或少地)这样做(在将my.exe复制到c:/1/c:/2/c:/3/ (通过c:/7/)之后):

代码语言:javascript
复制
cat(paste('CALL C:/1/my.exe',  ff[1:10], '/RUN=YES'), file='run1.bat', sep='\n')
cat(paste('CALL C:/2/my.exe', ff[11:20], '/RUN=YES'), file='run2.bat', sep='\n')
cat(paste('CALL C:/3/my.exe', ff[21:30], '/RUN=YES'), file='run3.bat', sep='\n')
cat(paste('CALL C:/4/my.exe', ff[31:40], '/RUN=YES'), file='run4.bat', sep='\n')
cat(paste('CALL C:/5/my.exe', ff[41:50], '/RUN=YES'), file='run5.bat', sep='\n')
cat(paste('CALL C:/6/my.exe', ff[51:60], '/RUN=YES'), file='run6.bat', sep='\n')
cat(paste('CALL C:/7/my.exe', ff[61:70], '/RUN=YES'), file='run7.bat', sep='\n')
parSapply(cl, c('run1.bat', 'run2.bat', 'run3.bat', 'run4.bat',
                'run5.bat', 'run6.bat', 'run7.bat'), system)

(上面,我没有让parSapplyff的70个元素分配给各个进程,而是在创建批处理文件时手动拆分它们,然后并行运行批处理文件。)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-30 19:33:26

听起来你的基本策略是唯一已知的解决问题的方法,但我认为可以做得更好。例如,可以通过让每个工作人员根据工作人员ID执行不同的命令行来避免创建.BAT文件。

代码语言:javascript
复制
# Assign worker ID's to each of the cluster workers
setid <- function(id) assign(".Worker.id", id, pos=globalenv())
clusterApply(cl, seq_along(cl), setid)

此外,您可能希望自动创建包含"my.exe“的目录。我也更喜欢使用符号链接而不是可执行文件的副本:

代码语言:javascript
复制
# Create directories containing a symlink to the real executable
exepath <- "C:/bin/my.exe"  # Path to the real executable
pdir <- getwd()  # Parent of the new executable directories
myexe <- file.path(pdir, sprintf("work_%d", seq_along(cl)), "my.exe")
for (x in myexe) {
  dir.create(dirname(x), showWarnings=FALSE)
  if (file.exists(x)) 
    unlink(x)
  file.symlink(exepath, x)
}

如果符号链接没有欺骗"my.exe“在所需目录中创建日志文件,则可以尝试使用"file.copy”而不是"file.symlink“。

现在,您可以使用以下方法运行并行作业:

代码语言:javascript
复制
# Each worker executes a different symlink to the real executable
worker.fun <- function(f, myexe) {
  system(sprintf("%s %s /RUN=YES", myexe[.Worker.id], f))
}
ff <- c('a', 'long', 'vector', 'of', 'file', 'paths')
parSapply(cl, ff, worker.fun, myexe)

您还可以删除所创建的目录,但由于使用了符号链接,它们不会占用太多空间,所以最好保留它们,特别是在调试/测试期间。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23530325

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档