在carrier::crate中嵌套用户函数,用于furrr::future_map时遇查找问题
问题描述
我用carrier::crate打包了嵌套函数:outer_foo调用inner_foo,并且把两个函数都传入了crate。本地调用outer_crate完全正常,打印outer_crate也能看到inner_foo已经被打包进去,但用future_map(设置multisession工作进程)调用时,却提示找不到inner_foo,只有手动把inner_foo设为全局变量传入才正常。只有用plan设置多进程时才会出问题,单进程下一切正常。
library(furrr) future::plan(multisession, workers = 3) inner_foo <- function(x){ x^2 } outer_foo <- function(x){ inner_foo(x) } outer_crate <- carrier::crate( function(x) outer_foo(x), outer_foo = outer_foo, inner_foo = inner_foo ) # 本地调用正常 outer_crate(3) # 打印可见inner_foo已被打包 outer_crate # 报错:找不到inner_foo future_map(1:3, outer_crate, .options = furrr_options(globals = FALSE)) # 手动传入inner_foo作为全局变量则正常运行 future_map(1:3, outer_crate, .options = furrr_options(globals = "inner_foo"))
原因与解决办法
问题根源
outer_foo的定义是在全局环境中调用inner_foo,哪怕你把inner_foo打包进了crate,outer_foo内部的调用逻辑依然是去全局环境找inner_foo——而multisession的子进程全局环境里没有这个函数,所以触发报错。
解决方式
不需要手动传全局变量,直接调整函数封装逻辑,让outer_foo能在crate的封闭环境里找到inner_foo即可:
方式1:在crate内重新定义outer_foo
直接在crate里写outer_foo的逻辑,让它绑定到crate的环境:
outer_crate <- carrier::crate( function(x) outer_foo(x), outer_foo = function(x) inner_foo(x), inner_foo = inner_foo )
方式2:把inner_foo内嵌到outer_foo里
如果函数逻辑不复杂,直接把inner_foo写到outer_foo内部,打包时会自动包含所有依赖:
outer_foo <- function(x){ inner_foo <- function(x){x^2} inner_foo(x) } outer_crate <- carrier::crate( function(x) outer_foo(x), outer_foo = outer_foo )
调整后,future_map即使设置globals = FALSE也能正常运行,因为所有依赖都被正确封装在crate的封闭环境中了。
内容的提问来源于stack exchange,提问作者Gerion
相关产品推荐
相关产品推荐

