Skip to contents

Set daemons, or persistent background processes, to receive mirai() requests. Specify n to create daemons on the local machine. Specify url to receive connections from remote daemons (for distributed computing across the network). Specify remote to optionally launch remote daemons via a remote configuration. Dispatcher (enabled by default) ensures optimal scheduling.

Usage

daemons(
  n,
  url = NULL,
  remote = NULL,
  dispatcher = TRUE,
  ...,
  seed = NULL,
  serial = NULL,
  tls = NULL,
  pass = NULL,
  .compute = "default"
)

Arguments

n

integer number of daemons to launch.

url

[default NULL] if specified, a character string comprising a URL at which to listen for remote daemons, including a port accepting incoming connections, e.g. 'tcp://hostname:5555' or 'tcp://10.75.32.70:5555'. Specify a URL with scheme 'tls+tcp://' to use secure TLS connections (for details see Distributed Computing section below). Auxiliary function host_url() may be used to construct a valid host URL.

remote

[default NULL] required only for launching remote daemons, a configuration generated by remote_config() or ssh_config().

dispatcher

[default TRUE] logical value, whether to use dispatcher. Dispatcher runs in a separate process to ensure optimal scheduling, although this may not always be required (for details see Dispatcher section below).

...

(optional) additional arguments passed through to daemon() if launching daemons. These include asyncdial, autoexit, cleanup, output, maxtasks, idletime and walltime.

seed

[default NULL] (optional) supply a random seed (single value, interpreted as an integer). This is used to inititalise the L'Ecuyer-CMRG RNG streams sent to each daemon. Note that reproducible results can be expected only for dispatcher = FALSE, as the unpredictable timing of task completions would otherwise influence the tasks sent to each daemon. Even for dispatcher = FALSE, reproducibility is not guaranteed if the order in which tasks are sent is not deterministic.

serial

[default NULL] (optional, requires dispatcher) a configuration created by serial_config() to register serialization and unserialization functions for normally non-exportable reference objects, such as Arrow Tables or torch tensors.

tls

[default NULL] (optional for secure TLS connections) if not supplied, zero-configuration single-use keys and certificates are automatically generated. If supplied, either the character path to a file containing the PEM-encoded TLS certificate and associated private key (may contain additional certificates leading to a validation chain, with the TLS certificate first), or a length 2 character vector comprising [i] the TLS certificate (optionally certificate chain) and [ii] the associated private key.

pass

[default NULL] (required only if the private key supplied to tls is encrypted with a password) For security, should be provided through a function that returns this value, rather than directly.

.compute

[default 'default'] character value for the compute profile to use (each compute profile has its own independent set of daemons).

Value

The integer number of daemons launched locally (zero if specifying url or using a remote launcher).

Details

Use daemons(0) to reset daemon connections:

  • All connected daemons and/or dispatchers exit automatically.

  • mirai reverts to the default behaviour of creating a new background process for each request.

  • Any unresolved 'mirai' will return an 'errorValue' 19 (Connection reset) after a reset.

  • Daemons must be reset before calling daemons() with revised settings for a compute profile. Daemons may be added at any time by using launch_local() or launch_remote() without needing to revise daemons settings.

If the host session ends, all connected dispatcher and daemon processes automatically exit as soon as their connections are dropped (unless the daemons were started with autoexit = FALSE). If a daemon is processing a task, it will exit as soon as the task is complete.

To reset persistent daemons started with autoexit = FALSE, use daemons(NULL) instead, which also sends exit signals to all connected daemons prior to resetting.

For historical reasons, daemons() with no arguments (other than optionally .compute) returns the value of status().

Local Daemons

Daemons provide a potentially more efficient solution for asynchronous operations as new processes no longer need to be created on an ad hoc basis.

Supply the argument n to set the number of daemons. New background daemon() processes are automatically created on the local machine connecting back to the host process, either directly or via dispatcher.

Dispatcher

By default dispatcher = TRUE launches a background process running dispatcher(). Dispatcher connects to daemons on behalf of the host, queues tasks, and ensures optimal scheduling.

Specifying dispatcher = FALSE, daemons connect directly to the host and tasks are distributed in a round-robin fashion. As tasks are queued at each daemon, optimal scheduling is not guaranteed as the duration of each task cannot be known a priori. Tasks can be queued at one daemon while others remain idle. However, this provides the most resource-light approach, suited to working with similar-length tasks, or where concurrent tasks typically do not exceed available daemons.

Distributed Computing

Specifying url as a character string allows tasks to be distributed across the network. n is only required in this case if providing a launch configuration to remote to launch remote daemons.

Supply a URL with a 'tcp://' scheme, such as 'tcp://10.75.32.70:5555'. The host / dispatcher listens at this address, utilising a single port. Individual daemons (started with daemon()) may then dial in to this URL. Host / dispatcher automatically adjusts to the number of daemons actually connected, allowing dynamic upscaling or downscaling as required.

Switching the URL scheme to 'tls+tcp://' automatically upgrades the connection to use TLS. The auxiliary function host_url() may be used to construct a valid host URL based on the computer's hostname.

IPv6 addresses are also supported and must be enclosed in square brackets [] to avoid confusion with the final colon separating the port. For example, port 5555 on the IPv6 loopback address ::1 would be specified as 'tcp://[::1]:5555'.

Specifying the wildcard value zero for the port number e.g. 'tcp://[::1]:0' will automatically assign a free ephemeral port. Use status() to inspect the actual assigned port at any time.

Specify remote with a call to remote_config() or ssh_config() to launch daemons on remote machines. Otherwise, launch_remote() may be used to generate the shell commands to deploy daemons manually on remote resources.

Compute Profiles

By default, the "default" compute profile is used. Providing a character value for .compute creates a new compute profile with the name specified. Each compute profile retains its own daemons settings, and may be operated independently of each other. Some usage examples follow:

local / remote daemons may be set with a host URL and specifying .compute as "remote", which creates a new compute profile. Subsequent mirai() calls may then be sent for local computation by not specifying the .compute argument, or for remote computation to connected daemons by specifying the .compute argument as "remote".

cpu / gpu some tasks may require access to different types of daemon, such as those with GPUs. In this case, daemons() may be called to set up host URLs for CPU-only daemons and for those with GPUs, specifying the .compute argument as "cpu" and "gpu" respectively. By supplying the .compute argument to subsequent mirai() calls, tasks may be sent to either cpu or gpu daemons as appropriate.

Note: further actions such as resetting daemons via daemons(0) should be carried out with the desired .compute argument specified.

Examples

if (FALSE) { # interactive()
# Create 2 local daemons (using dispatcher)
daemons(2)
status()
# Reset to zero
daemons(0)

# Create 2 local daemons (not using dispatcher)
daemons(2, dispatcher = FALSE)
status()
# Reset to zero
daemons(0)

# Set up dispatcher accepting TLS over TCP connections
daemons(url = host_url(tls = TRUE))
status()
# Reset to zero
daemons(0)

# Set host URL for remote daemons to dial into
daemons(url = host_url(), dispatcher = FALSE)
status()
# Reset to zero
daemons(0)

# Use with() to evaluate with daemons for the duration of the expression
with(
  daemons(2),
  {
    m1 <- mirai(Sys.getpid())
    m2 <- mirai(Sys.getpid())
    cat(m1[], m2[], "\n")
  }
)

if (FALSE) { # \dontrun{

# Launch daemons on remotes 'nodeone' and 'nodetwo' using SSH
# connecting back directly to the host URL over a TLS connection:
daemons(
  url = host_url(tls = TRUE),
  remote = ssh_config(c('ssh://nodeone', 'ssh://nodetwo'))
)

# Launch 4 daemons on the remote machine 10.75.32.90 using SSH tunnelling:
daemons(
  n = 4,
  url = local_url(tcp = TRUE),
  remote = ssh_config('ssh://10.75.32.90', tunnel = TRUE)
)

} # }
}