-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue with Sequential and Multicore futures finding variables that they shouldn't #608
Comments
Great to see this issue has already been reported in such detail. Just today I failed to reproduce results from a simulation study run with future.apply 1.8.1 + future 1.21.0 for the same reason (I guess). It breaks when going from future 1.21.0 to future >= 1.22.1. r0 <- local({
mu <- 0
function () mu
})
r1 <- local({
mu <- 1
function () mu
})
replicate(3, r1()-r0())
#> [1] 1 1 1
library("future.apply")
plan(sequential) # or multicore
future_replicate(3, r1()-r0())
#> [1] 0 0 0
## "Solution" 1:
future_replicate(3, r1()-r0(), future.globals = "idontexist")
#> [1] 1 1 1
## "Solution" 2:
options(future.globals.keepWhere = TRUE)
future_replicate(3, r1()-r0())
#> [1] 1 1 1 |
Thanks both. This looks quite serious, especially since it can be a silent bug that produces incorrect results. I suspect it's due to the following future 1.22.0 update (#515):
which, if my memory is correct, was quite a challenging issue to solve. I guess I should have been alerted by those unusually tricky challenges. |
FWIW, here you're effectively skipping the identification of globals, meaning an alternative would have been to use |
@bastistician , a version of your example, without future.apply, is: library(future)
plan(sequential)
r0 <- local({
mu <- 0
function() mu
})
r1 <- local({
mu <- 1
function() mu
})
truth <- r1() - r0()
print(truth)
#> [1] 1
f <- future(r1() - r0())
y <- value(f)
print(y)
#> [1] 0
stopifnot(identical(y, truth))
#> Error: identical(y, truth) is not TRUE |
…rom the function for some future backends, including sequential and multicore [#608]
Update: I've just released future 1.26.1, to fix some urgent bugs, but it does not fix this problem. I've been doing quite some work the last four weeks, and I was hoping to fix the long outstanding problem once and for all. It's complicated because when serializing a function/closure we want to make sure all:
These properties and objectives compete with each other in the sense that, solving one, tends to break another one. At least, if one tries to do a "quick" fix (e.g. So, to solve this once and for all, I need to be able to deconstruct functions and their environments (possibly several layers) and then rebuild them again so that the global environment is not part of the equation and ideally with "cargo" objects pruned away. On top of this, I need to do it so that functions that share the same environment (e.g. |
(This is an issue I discovered when running my furrr tests interactively. It doesn't occur on CI, or on CRAN, or when I do a full
check()
locally, and I think that has to do with the environments involved)In this example,
fn()
should not be able to be evaluated, because its function environment does not containy
.However, if you put it in a Sequential or Multicore future and define
y
in the environment where the future was created, then it can be evaluated and "works" even though it shouldn't. Notably,y
doesn't even show up in the list of globals for the future.This doesn't happen for Multisession futures:
I noticed that in
getGlobalsAndPackages()
, thefuture.globals.keepWhere
option controls whether or not thewhere
environments are removed by setting them toemptyenv()
. Removing them seems reasonable, and was added in #475.However, this setting of the
where
environment toemptyenv()
conflicts withassign_globals()
used in running sequential and multicore futures. Here is where that is used for sequential futures:https://github.com/HenrikBengtsson/future/blob/82d4817214900af156dee63b567d00e8229000bb/R/UniprocessFuture-class.R#L65
assign_globals()
will reset the environment of the global to a child of the future's environment IF it was theemptyenv()
. Because of thefuture.globals.keepWhere
branch, the global's environment is identical withemptyenv()
, so this runs. So that sets the environment of thefn
global to a child environment of the future itself, i.e. it basically uses theenvir
offuture(envir = parent.frame())
, and this hasy
in it.https://github.com/HenrikBengtsson/future/blob/230e428c8a8c18e12b01f3050a90c3adab579024/R/utils.R#L179-L182
So it looks like that FIXME note about being overly conservative may actually be introducing a bug.
We can confirm all this by setting
future.globals.keepWhere
toFALSE
to try not setting thewhere
environments toemptyenv()
(which avoids resetting them to the future's env):The text was updated successfully, but these errors were encountered: