Skip to content

Commit

Permalink
implements '...' mapping to globals
Browse files Browse the repository at this point in the history
  • Loading branch information
shikokuchuo committed Apr 9, 2024
1 parent 8143e98 commit 647e65d
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 82 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: mirai
Type: Package
Title: Minimalist Async Evaluation Framework for R
Version: 0.13.1.9011
Version: 0.13.1.9012
Description: Lightweight parallel code execution and distributed computing.
Designed for simplicity, a 'mirai' evaluates an R expression asynchronously,
on local or network resources, resolving automatically upon completion.
Expand Down
3 changes: 2 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# mirai 0.13.1.9011 (development)
# mirai 0.13.1.9012 (development)

* `mirai()` behaviour changed such that '...' args are now assigned to the global environment of the daemon process.
* Adds `with()` method for mirai daemons, allowing for example: `with(daemons(4), {expr})`, where the daemons last for the duration of 'expr'.
* Adds `register_cluster()` for registering 'miraiCluster' as a parallel Cluster type (requires R >= 4.4).
* Adds `is.promising()` method for 'mirai' for the promises package.
Expand Down
4 changes: 3 additions & 1 deletion R/daemon.R
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ handle_mirai_error <- function(e) invokeRestart("mirai_error", e, sys.calls())

handle_mirai_interrupt <- function(e) invokeRestart("mirai_interrupt")

eval_mirai <- function(._mirai_.)
eval_mirai <- function(._mirai_.) {
list2env(._mirai_.[["._mirai_globals_."]], envir = .GlobalEnv)
withRestarts(
withCallingHandlers(
eval(expr = ._mirai_.[[".expr"]], envir = ._mirai_., enclos = NULL),
Expand All @@ -205,6 +206,7 @@ eval_mirai <- function(._mirai_.)
mirai_error = mk_mirai_error,
mirai_interrupt = mk_interrupt_error
)
}

dial_and_sync_socket <- function(sock, url, asyncdial, tls = NULL) {
cv <- cv()
Expand Down
1 change: 1 addition & 0 deletions R/mirai-package.R
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
dot_required = "'.' must be an element of the character vector(s) supplied to 'args'",
missing_expression = "missing expression, perhaps wrap in {}?",
missing_url = "at least one URL must be supplied for 'url' or 'n' must be at least 1",
named_args = "all '...' arguments must be named",
n_one = "'n' must be 1 or greater",
n_zero = "the number of daemons must be zero or greater",
numeric_n = "'n' must be numeric, did you mean to provide 'url'?",
Expand Down
33 changes: 15 additions & 18 deletions R/mirai.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@
#' wrapped in \{ \} where necessary), \strong{or} a language object passed
#' by \link{name}.
#' @param ... (optional) named arguments (name = value pairs) specifying
#' objects referenced in '.expr'. Used in addition to, and taking precedence
#' over, any arguments specified via '.args'.
#' objects referenced in '.expr'. These are placed in the global environment
#' of the evaluation process, unlike those supplied to '.args' below.
#' @param .args (optional) \strong{either} a list of objects passed by
#' \link{name} (found in the current scope), \strong{or else} a list of
#' name = value pairs, as in '...'.
#' name = value pairs, as in '...'. These remain local to the evaluation
#' environment.
#' @param .timeout [default NULL] for no timeout, or an integer value in
#' milliseconds. A mirai will resolve to an 'errorValue' 5 (timed out) if
#' evaluation exceeds this limit.
Expand All @@ -49,12 +50,14 @@
#' 'mirai' has yet to resolve and FALSE otherwise. This is suitable for use
#' in control flow statements such as \code{while} or \code{if}.
#'
#' Alternatively, to call (and wait for) the result, use \code{\link{call_mirai}}
#' on the returned mirai. This will block until the result is returned.
#' Alternatively, to call (and wait for) the result, use
#' \code{\link{call_mirai}} on the returned mirai. This will block until the
#' result is returned.
#'
#' The expression '.expr' will be evaluated in a separate R process in a
#' clean environment, which is not the global environment, consisting only
#' of the named objects passed as '...' and/or the list supplied to '.args'.
#' clean environment (not the global environment), consisting only of the
#' objects in the list supplied to '.args', with the named objects passed as
#' '...' assigned to the global environment of that process.
#'
#' Specify '.compute' to send the mirai using a specific compute profile (if
#' previously created by \code{\link{daemons}}), otherwise leave as 'default'.
Expand Down Expand Up @@ -109,19 +112,11 @@
#' call_mirai(m)[["data"]]
#' unlink(file)
#'
#' # specifying global variables using list2env(envir = .GlobalEnv) in '.expr'
#' # evaluating scripts using source() in '.expr'
#' n <- 10L
#' file <- tempfile()
#' cat("r <- rnorm(n)", file = file)
#' globals <- list(file = file, n = n)
#' m <- mirai(
#' {
#' list2env(globals, envir = .GlobalEnv)
#' source(file)
#' r
#' },
#' globals = globals
#' )
#' m <- mirai({source(file); r}, file = file, n = n)
#' call_mirai(m)[["data"]]
#' unlink(file)
#'
Expand All @@ -140,7 +135,9 @@ mirai <- function(.expr, ..., .args = list(), .timeout = NULL, .compute = "defau
missing(.expr) && stop(._[["missing_expression"]])

expr <- substitute(.expr)
arglist <- list(..., .expr = if (is.symbol(expr) && is.language(.expr)) .expr else expr)
globals <- list(...)
all(nzchar(names(globals))) || stop(._[["named_args"]])
arglist <- list(._mirai_globals_. = globals, .expr = if (is.symbol(expr) && is.language(.expr)) .expr else expr)
if (length(.args))
arglist <- c(if (is.null(names(.args))) `names<-`(.args, as.character(substitute(.args)[-1L])) else .args, arglist)
data <- list2env(arglist, envir = NULL, parent = .GlobalEnv)
Expand Down
7 changes: 4 additions & 3 deletions man/everywhere.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 12 additions & 17 deletions man/mirai.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 42 additions & 41 deletions vignettes/mirai.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ Upon completion, the 'mirai' resolves automatically to the evaluated result.

```r
m$data |> str()
#> num [1:100000000] -0.827 22.238 -9.488 0.95 -5.677 ...
#> num [1:100000000] -32.008 0.607 3.089 -0.95 1.566 ...
```
Alternatively, explicitly call and wait for the result using `call_mirai()`.

```r
call_mirai(m)$data |> str()
#> num [1:100000000] -0.827 22.238 -9.488 0.95 -5.677 ...
#> num [1:100000000] -32.008 0.607 3.089 -0.95 1.566 ...
```
For easy programmatic use of `mirai()`, '.expr' accepts a pre-constructed language object, and also a list of named arguments passed via '.args'. So, the following would be equivalent to the above:

Expand All @@ -82,7 +82,7 @@ args <- list(m = runif(1), n = 1e8)
m <- mirai(.expr = expr, .args = args)

call_mirai(m)$data |> str()
#> num [1:100000000] 0.0965 1.5038 -23.8437 -1.177 3.7363 ...
#> num [1:100000000] -7.292 -0.505 3.424 0.976 -0.555 ...
```

[&laquo; Back to ToC](#table-of-contents)
Expand Down Expand Up @@ -163,9 +163,10 @@ for (i in 1:10) {
#> iteration 5 successful
#> iteration 6 successful
#> iteration 7 successful
#> Error: random error
#> iteration 8 successful
#> iteration 9 successful
#> Error: random error
#>
#> iteration 10 successful
```
Further, by testing the return value of each 'mirai' for errors, error-handling code is then able to automate recovery and re-attempts, as in the above example. Further details on [error handling](#errors-interrupts-and-timeouts) can be found in the section below.
Expand Down Expand Up @@ -198,12 +199,12 @@ status()
#>
#> $daemons
#> i online instance assigned complete
#> abstract://6338f92a4c90df9366420eb2 1 1 1 0 0
#> abstract://1478413c7128fe0d9e464bd1 2 1 1 0 0
#> abstract://94034b9215dcf7bb61a54244 3 1 1 0 0
#> abstract://17b1eb18e137541aee5c14ed 4 1 1 0 0
#> abstract://66a846457f560f81f5249bb6 5 1 1 0 0
#> abstract://c1d30dd7e5d050ae412b5e75 6 1 1 0 0
#> abstract://91a6b62202d00d187aa67d21 1 1 1 0 0
#> abstract://521492b2f29ecc3a83804ecb 2 1 1 0 0
#> abstract://8d3bbd54bde058b29fd61f02 3 1 1 0 0
#> abstract://668bb2864db645ab8adf8c61 4 1 1 0 0
#> abstract://1f14fca887b16b53cdf259c6 5 1 1 0 0
#> abstract://6e076a460da28b3277b15eee 6 1 1 0 0
```
The default `dispatcher = TRUE` creates a `dispatcher()` background process that connects to individual daemon processes on the local machine. This ensures that tasks are dispatched efficiently on a first-in first-out (FIFO) basis to daemons for processing. Tasks are queued at the dispatcher and sent to a daemon as soon as it can accept the task for immediate execution.

Expand Down Expand Up @@ -232,7 +233,7 @@ status()
#> [1] 6
#>
#> $daemons
#> [1] "abstract://9c105907ae39a12b31345503"
#> [1] "abstract://89fbf96488689bce25401057"
```
This implementation sends tasks immediately, and ensures that tasks are evenly-distributed amongst daemons. This means that optimal scheduling is not guaranteed as the duration of tasks cannot be known *a priori*. As an example, tasks could be queued at a daemon behind a long-running task, whilst other daemons are idle having already completed their tasks.

Expand Down Expand Up @@ -322,7 +323,7 @@ By specifying `dispatcher = FALSE`, remote daemons connect directly to the host

```r
daemons(url = host_url(), dispatcher = FALSE)
#> [1] "tcp://hostname:44455"
#> [1] "tcp://hostname:46319"
```
Note that above, calling `host_url()` without a port value uses the default of '0'. This is a wildcard value that will automatically cause a free ephemeral port to be assigned. The actual assigned port is provided in the return value of the call, or it may be queried at any time via `status()`.

Expand All @@ -336,7 +337,7 @@ status()
#> [1] 0
#>
#> $daemons
#> [1] "tcp://hostname:44455"
#> [1] "tcp://hostname:46319"
```
To reset all connections and revert to default behaviour:

Expand Down Expand Up @@ -406,10 +407,10 @@ daemons(n = 2, url = host_url())

launch_remote(1:2)
#> [1]
#> Rscript -e "mirai::daemon('tcp://hostname:44071',rs=c(10407,-1933051572,-585663011,-1156513030,-1396698061,722060248,-1180972039))"
#> Rscript -e "mirai::daemon('tcp://hostname:37381',rs=c(10407,-946792896,1133515073,2088705550,1147127607,1694978572,-1743564899))"
#>
#> [2]
#> Rscript -e "mirai::daemon('tcp://hostname:40809',rs=c(10407,-396450800,1726980926,682016630,245943105,-949728259,-647653620))"
#> Rscript -e "mirai::daemon('tcp://hostname:37391',rs=c(10407,1830841599,73488881,-1705911956,24477530,1409242893,1810474992))"

daemons(0)
#> [1] 0
Expand Down Expand Up @@ -437,37 +438,37 @@ The generated self-signed certificate is available via `launch_remote()`. This f
```r
launch_remote(1)
#> [1]
#> Rscript -e "mirai::daemon('wss://hostname:43083/1',tls=c('-----BEGIN CERTIFICATE-----
#> Rscript -e "mirai::daemon('wss://hostname:40351/1',tls=c('-----BEGIN CERTIFICATE-----
#> MIIFNzCCAx+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAzMREwDwYDVQQDDAhrdW1h
#> bW90bzERMA8GA1UECgwITmFub25leHQxCzAJBgNVBAYTAkpQMB4XDTAxMDEwMTAw
#> MDAwMFoXDTMwMTIzMTIzNTk1OVowMzERMA8GA1UEAwwIa3VtYW1vdG8xETAPBgNV
#> BAoMCE5hbm9uZXh0MQswCQYDVQQGEwJKUDCCAiIwDQYJKoZIhvcNAQEBBQADggIP
#> ADCCAgoCggIBAMZjegHQL3CiAedFCNr2Em8EXo64g6h/WRYrz0NyyZekhEH4SrHb
#> bpAe4aSxrub7cC67aV2oU+JNHMh+xVFN/5cY97iEFrCcWFwSKxOXfV6q/2UG8SA7
#> AFXTT2IY8o0nK5DMwi1whVRMLTwW+VqmWXdslIde0H5Vf+nCk/zLOgNgbqlp1ntr
#> MFIB8fyPWcdnJvuOf8mOxft8RRfId5nQJ3rVQIZwajhuqxH9ugVlIJQE2IOOKchr
#> cl9YoRFkuaKgkTu6bPTnkNzX6QTrR8+m23xXR1U/UPv4Dt4bHXtrAMdR1cHHVZ++
#> db4h3amIm5jfTn82TWtMtWGNHcgExndE6PrLIslBAaHOetsQz7IvidUeGtzY4Sf/
#> nR2/vsTXGabYrRF+PfNmiiDbsesZuUPEmug+whLGaBKC1nOX72VcR982JKbH5hdv
#> 5KxsDXXS1Vrsg1iQcW7WpQGk3Pstlaq00IwJLbD2Or1lyQEGOw/+56ZTIRPDbiLj
#> fp6V/dhwe3jHWWn5Mm7i0NjRNhB+2mkJ2pwkjmIZ74POoqJ4WTSa7JJ1vL3MgpnG
#> Tbjo/OAqWkGMwm0cSqefOt+oR6KGgTz0PbQEjc2982P3GSXo5s3FnUAFodUGmHae
#> ILA6yX3IIenrlvZm0TRhpEZ5UqByvGB68jLXwJLrwaj77ku62qtvmQsrAgMBAAGj
#> VjBUMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFArUeAN6YURHYB1C2pq5
#> zB6Usp34MB8GA1UdIwQYMBaAFArUeAN6YURHYB1C2pq5zB6Usp34MA0GCSqGSIb3
#> DQEBCwUAA4ICAQCGfWJCaXYkxWOf7NKIwnrSi73teJBC0RikNGh98YMbjBnCvwOt
#> jHhhWUXBVYQ3qMWkyXdK5/c3ccJDvq8cln5oRFbdoibUsz4FCKXH/MM3MXK/K2Vw
#> g6PH/JwipURnWJbQRRfR0mpmCNItTcML7f95BB8VYuy5udf7W6Wj2E1NeERALQVy
#> LHnNwDkKj1fuFKF1xwefomovOODYqR5oip3WYEUJ8u6b/KP3x+juRbvgLJ2fIupB
#> ImKpcGiYipY9bTuK+Ky8ucuiUaj6WTx37Vupqt+B9e7vXQ5HOSPGsnaCxrZ+bxx4
#> IpwL8vTA45BsDSFUCwJ0Q2TEKxFaItz1qKJPhTbS4kBpOsVruPDlR5q0hFSaL6K5
#> VkeoXJa6V6GlLYiEmpgBm74ApboHm7M5plsPSAir/iE66LWVa7/DLwHF0x4i6uBj
#> echbAfZVD7s1/uvbhuBGUdgnOg959DakF4KV5O24lHe3re3Oh6CB2sQCrgSxdMJl
#> gQtJaM5ZRbLUn1sBkNLV4ViKI3A9+4FS3ze0e9/ECWU1jF9dxbnnTjNB2BTM1Nrq
#> Rj7vzekKIUgnJlNILbVXrcykN/v+PK6+Xq49gZ+gdAMh5bqv14N1NRkx0Ekp+sFk
#> c+HwxXfT5+3tJsmmLud55atLByAbVjlpv9dvioTYtp7b1tRmbC+h+9ChHQ==
#> ADCCAgoCggIBAJjDVsNb6Qy/hlYU2xULH2PmSIS8bsSg4T1RAijk7DDsJbd2ZZmo
#> lpJpEa5XgLil0orKQC+iuIoqfKka7OZ1r+YfwcSfVHXYX0VUY4e3gugeld7E+rls
#> r0eTZrRRkU0I4r+pAL5F0gUc5UJj6GBwmFlDwfjmRIiQV0iaYkWPKiikh4kTR3vN
#> QsOKwIm6RkEHzcZQ6xwry3zonE/+Z5GScnFnbBxjIL4R57ZjRYs3FmROF+EXvRQe
#> UD7HJifLy4JhH+gHGDhphG8jEfLbPN6DsiHKc7tSdRrzdufgUhpKQFhRRFPZ6d3W
#> TQJkyarF+1zW+tgKWJ1jtyhAfYNLUb8XKNym6w6wsz8KcSSrgu0TN1cd5emrK2bN
#> /fgiQjQ1g3v1rvi7uZVMNuDMNRmFkvei9NNcejqzp0LDizEaTLIqoYq0eD5VQLtP
#> YUNnaPv9saHGEzHqKS9M8OGCKuaztZt+OLWgJpkatCb2ZZFLRrqNhga4hfm2xULZ
#> IZ1pUcLJbLMJgIgtLlMyi6eMd9vulNxf7fFFBodCmn4afYidu4rNvMnA/dPjEPRE
#> FOeJ5+KN7uOA8TkpBfXBDEgKforOhhZaS/YJK3mE9aQ+AUN18BjTnJYZ9aX9vGmG
#> ma2aQOdhVqYxBmaGnbeiN0EIU+cgv4MtnXm9YDBSDnm9klmbMQfIweHBAgMBAAGj
#> VjBUMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFEToJuFOCIzGXwxgCP1U
#> 0MLhtawTMB8GA1UdIwQYMBaAFEToJuFOCIzGXwxgCP1U0MLhtawTMA0GCSqGSIb3
#> DQEBCwUAA4ICAQBw1bKLvUZ8C2mDSlMYtEPh/W8iBPp4g1oLy8+tIM1J9xwdwgVm
#> 8UkWjN1UMia2DRc5+jALmvdQbQqfo1kJTDNahfwunSSTnZ941ShNzcYgarYn/FSa
#> amxDpWv6L7lDBGzOVtHBVGhGvYZBCwg6fjUb0tQEUm0+ANxhbRORQQlI5zpvEqSv
#> ZZJNsfPfTW181U55V7aq6lA0wRChHp8QYaAoCCCX2zuMyQieyGOAJxf39ue1FbWO
#> O5Zk2tvRNfBeKoRQ2DjdnsW92rTCv1P3j2ScdpjiNw19kpP970LSVM7lw5u3LHoS
#> iCWwKyYFl2KX/kM7Wp6S1WdqCX/yRjpLzALwx477otvEZxcoFJEkDExKgOWpHU/d
#> JVhyUk+aYBGQjfM5QqgYoS6loe1y3UrX4Otbj3MdoRHdlkG+XLAIjcuVC3L8aPWH
#> IqykoKAUntr4kxXMSW5wsQ1gfw8Wp71E+P/DyWrqtslGpN3wkvAjHeuUmFnCfPSs
#> 8SnsZH5a6mAlFctcEdUDyaPedae+y9lSrkp6RVeZGbWBcYkkgLpcryuM9QhDixPv
#> LaDcXdqRxoDF8n08YTG1VrZ60vGPjy4Lgh9VgNP3LKmJ0Z5ctK2Pq9RwS5BX8iLT
#> 8vpazCHf7WaWxpTfmg23oq9VsEWlcSRbTH2MLsTFdt0WM1md20J/s3PG1w==
#> -----END CERTIFICATE-----
#> ',''),rs=c(10407,-735603597,2058270488,-733161927,-1096716122,1252369135,-757556124))"
#> ',''),rs=c(10407,1597845323,-1901023728,-362663215,-536326562,553617223,-305860900))"
```
The printed value may be deployed directly on a remote machine.

Expand Down

0 comments on commit 647e65d

Please sign in to comment.