--- title: "7. Community FAQs" vignette: > %\VignetteIndexEntry{7. Community FAQs} %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} --- ### Table of Contents 1. [Migration from future_promise](#migration-from-future_promise) 2. [Setting the Random Seed](#setting-the-random-seed) ### Migration from future_promise It should be mostly straightforward translating ExtendedTask code that was originally written for use with a `future_promise()`. The most important difference is that a `future_promise()` tries to infer all the global variables that are required by the expression. However this can easily run into edge cases, or behave in a way that you would not expect. As this behaviour is not transparent, in the best case you will know something has gone wrong, but in the worst case could silently produce the wrong result. In both cases, you would not know until you are trying to debug the situation. A mirai on the other hand, requires that the expression be self-contained, hence any variables or helper functions are passed in via the `...` of `mirai()`. This simple requirement allows for transparent and reliable behaviour that remains completely robust over time. It also means that you can easily reason about your code, and is designed to save you time in the long run. #### Special Case: `...` Example A Shiny app may use the following `future_promise()` code within the server component: ```r func <- function(x, y){ Sys.sleep(y) runif(x) } task <- ExtendedTask$new( function(...) future_promise(func(...)) ) |> bind_task_button("btn") observeEvent(input$btn, task$invoke(input$n, input$delay)) ``` The equivalent may be achieved in `mirai()` in the following way: ```r task <- ExtendedTask$new( function(...) mirai(func(...), func = func, .args = environment()) ) |> bind_task_button("btn") ``` 1. `environment()` captures the `...` to be used by the function within the mirai expression, and can be supplied via `.args`. 2. The definition for `func` is passed through in the usual way. *This example comes from a question raised by Simon Smart.* [« Back to ToC](#table-of-contents) ### Setting the Random Seed The following example was raised as being potentially counter-intuitive, given that default 'cleanup' settings at each daemon ensures that variables in the global environment, of which `.Random.seed` is one, do not carry over to subsequent runs. ``` r library(mirai) daemons(4) #> [1] 4 vec <- 1:3 vec2 <- 4:6 # Returns different values: good mirai_map(list(vec, vec2), \(x) rnorm(x))[] #> [[1]] #> [1] 0.4182510 -0.1533799 0.4631808 #> #> [[2]] #> [1] 0.7438234 -1.5495708 1.3562752 # Set the seed in the function mirai_map(list(vec, vec2), \(x) { set.seed(123) rnorm(x) })[] #> [[1]] #> [1] -0.9685927 0.7061091 1.4890213 #> #> [[2]] #> [1] -0.9685927 0.7061091 1.4890213 # Do not set the seed in the function: still identical results? mirai_map(list(vec, vec2), \(x) rnorm(x))[] #> [[1]] #> [1] -1.8150926 0.3304096 -1.1421557 #> #> [[2]] #> [1] -1.8150926 0.3304096 -1.1421557 daemons(0) #> [1] 0 ``` The reason the change in random seed persists in all circumstances is due to this being a special case, arising from the use of L'Ecuyer CMRG streams to provide parallel-safe random numbers. Streams can be thought of as entry points to the psuedo random number line far away from each other to ensure that random results in each daemon are independent from one another. The random seed is not reset after each mirai call to ensure that however many random draws are made in any mirai call, the next random draw follows on in the stream, and hence have the desired statistical properties. Hence normally, the random seed should be set once on the host process when daemons are created, rather than in each daemon. If it is required to set the seed in each daemon, this should be done using an independent method and set each time random draws are required. Another option would be to set the random seed within a local execution scope to prevent the global random seed on each daemon from being affected. *This example comes from a question raised by Etienne Bacher.* [« Back to ToC](#table-of-contents)