为何pkgload::load_all()加载的开发中R包无法在callr::r()中调用
原理说明
首先,pkgload::load_all()的核心作用是将开发状态的包模拟安装到当前父R会话的内存中,它不会将包写入R的系统默认或用户自定义库路径,仅在当前会话生效。
而callr::r()/callr::r_bg()启动的是完全独立的全新R子进程,子进程会初始化独立的运行环境:
- 无法访问父进程内存中已经加载的未安装包对象
- 默认使用系统全局的
.libPaths(),不会包含你开发包的源码路径,也没有你开发包的正式安装版本
因此子进程调用mytest::hello()时会提示包不存在,只有当你正式安装mytest到R能识别的库路径后,子进程才能正常找到该包。
可行解决方案
方案1:子进程内主动执行pkgload::load_all(开发阶段最优)
直接将开发包的根路径作为参数传入子进程,在子进程内模拟加载开发包,无需正式安装:
# 替换为你的mytest包的本地根目录路径,若当前工作目录就是包根目录可直接用getwd() pkg_root <- getwd() callr::r(function(pkg_path) { # 子进程内加载开发包 pkgload::load_all(pkg_path, quiet = TRUE) # 调用包内函数 mytest::hello() }, args = list(pkg_path = pkg_root))
如果使用后台运行的r_bg,逻辑完全一致:
bg_proc <- callr::r_bg(function(pkg_path) { pkgload::load_all(pkg_path, quiet = TRUE) return(mytest::hello()) }, args = list(pkg_path = getwd())) # 等待进程运行结束后获取结果 bg_proc$wait() bg_proc$get_result()
方案2:临时安装开发包到可识别路径
如果你不想在子进程依赖pkgload,可先将开发包临时安装到R的库路径中,再执行callr调用:
# 临时安装当前开发包 devtools::install_local(force = TRUE, quiet = TRUE) # 此时子进程可直接找到已安装的mytest包 callr::r(function() { mytest::hello() })
注意:方案2会覆盖你之前正式安装的mytest版本,开发调试更推荐使用方案1,不会修改已安装的正式包。
内容的提问来源于stack exchange,提问作者josep maria porrà
相关产品推荐
相关产品推荐

