Set 'daemons' or background persistent server processes receiving
mirai
requests. These are, by default, automatically
created on the local machine. Alternatively, a client URL may be
specified to receive connections from remote servers started with
server
for distributing tasks across the network. Daemons
may take advantage of the dispatcher, which ensures that tasks are
assigned to servers efficiently on a FIFO basis, or else the low-level
approach of distributing tasks to servers in an even fashion.
daemons(
n,
url = NULL,
dispatcher = TRUE,
refhook = NULL,
...,
.compute = "default"
)
integer number of daemons (server processes) to set.
[default NULL] if specified (for connecting to remote servers), the client URL as a character vector, including a port accepting incoming connections (and optionally for websockets a path) e.g. 'tcp://192.168.0.2:5555' or 'ws://192.168.0.2:5555/path'.
[default TRUE] logical value whether to use dispatcher. Dispatcher is a background process that connects to servers on behalf of the client and ensures FIFO scheduling, queueing tasks if necessary (see Dispatcher section below).
[default NULL] maps to the 'refhook' argument of
serialize
and unserialize
for providing a
hook function to handle reference objects. As the same function is used
in both cases, it should contain the necessary logic to distinguish
between them as required. Accepts a function or function encoded via
base64enc
.
additional arguments passed through to dispatcher
if
using dispatcher and/or server
if launching local daemons.
[default 'default'] character compute profile to use for creating the daemons (each compute profile has its own set of daemons for connecting to different resources).
Setting daemons: integer number of daemons set, or the character client URL.
Viewing current status: a named list comprising:
connections - number of active connections at the client. Always 1L when using dispatcher as there is only a single connection to the dispatcher, which then in turn connects to the servers.
daemons - if using dispatcher: a status matrix (see Status Matrix section below), or else an integer 'errorValue' if communication with the dispatcher was unsuccessful. If not using dispatcher: the number of daemons set, or else the client URL.
For viewing the currrent status, specify daemons()
with no
arguments.
Use daemons(0)
to reset daemon connections:
A reset is required before revising settings for the same compute profile, otherwise changes are not registered.
All connected daemons and/or dispatchers exit automatically.
mirai reverts to the default behaviour of creating a new background process for each request.
When specifying a client URL, all daemons dialing into the client are detected automatically and resources may be added or removed at any time.
If the client session ends, for whatever reason, all connected dispatcher and daemon processes automatically exit as soon as their connections are dropped. If a daemon is processing a task, it will exit as soon as the task is complete.
If setting 'refhook', the same function must be provided for all compute
profiles. Servers launched manually, i.e. other than through this
function or launch_server
, must use the same 'refhook'
argument to ensure seamless operation.
By default dispatcher = TRUE
. This launches a background process
running dispatcher
. A dispatcher connects to servers on
behalf of the client and queues tasks until a server is able to begin
immediate execution of that task, ensuring FIFO scheduling. Dispatcher
uses synchronisation primitives from nanonext
, waiting rather than
polling for tasks, which is efficient both in terms of consuming no
resources while waiting, and also being fully synchronised with events
(having no latency).
By specifying dispatcher = FALSE
, servers connect to the client
directly rather than through a dispatcher. The client sends tasks to
connected servers immediately in an evenly-distributed fashion. However,
optimal scheduling is not guaranteed as the duration of tasks cannot be
known a priori, such that tasks can be queued at a server behind
a long-running task while other servers remain idle. Nevertheless, this
provides a resource-light approach suited to working with similar-length
tasks, or where concurrent tasks typically do not exceed available 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
server
processes are automatically created on the local
machine connecting back to the client process, either directly or via a
dispatcher.
Specifying 'url' allows tasks to be distributed across the network.
The client URL should be in the form of a character string such as:
'tcp://192.168.0.2:5555' at which server processes started using
server
should connect to.
Alternatively, to listen to port 5555 on all interfaces on the local host, specify either 'tcp://:5555', 'tcp://*:5555' or 'tcp://0.0.0.0:5555'.
Specifying the wildcard value zero for the port number e.g. 'tcp://:0' or
'ws://:0' will automatically assign a free ephemeral port. Use
daemons()
to inspect the actual assigned port at any time.
With Dispatcher
When using dispatcher, it is recommended to use a websocket URL rather than TCP, as this requires only one port to connect to all servers: a websocket URL supports a path after the port number, which can be made unique for each server.
Specifying a single client URL such as 'ws://192.168.0.2:5555' with
n = 6
will automatically append a sequence to the path, listening
to the URLs 'ws://192.168.0.2:5555/1' through 'ws://192.168.0.2:5555/6'.
Alternatively, specify a vector of URLs to listen to arbitrary port numbers / paths. In this case it is optional to supply 'n' as this can be inferred by the length of vector supplied.
Individual server
instances should then be started on the
remote resource, which dial in to each of these client URLs. At most one
server should be dialled into each URL at any given time.
The dispatcher automatically adjusts to the number of servers actually connected. Hence it is possible to dynamically scale up or down the number of servers as required, subject to the maximum number initially specified.
Alternatively, supplying a single TCP URL will listen on a block of URLs
with ports starting from the supplied port number and incrementing by one
for 'n' specified e.g. the client URL 'tcp://192.168.0.2:5555' with
n = 6
listens to the contiguous block of ports 5555 through 5560.
Without Dispatcher
A TCP URL may be used in this case as the client listens at only one address, utilising a single port.
The network topology is such that server daemons (started with
server
) or indeed dispatchers (started with
dispatcher
) dial into the same client URL.
'n' is not required in this case, and disregarded if supplied, as network resources may be added or removed at any time. The client automatically distributes tasks to all connected servers and dispatchers.
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 via a client URL and creating a new compute profile by specifying '.compute' as 'remote'. Subsequent mirai calls may then be sent for local computation by not specifying its '.compute' argument, or for remote computation to connected daemons by specifying its '.compute' argument as 'remote'.
cpu / gpu some tasks may require access to different classes of
server, such as those with GPUs. In this case, daemons()
may be
called twice to set up client URLs for CPU-only and GPU servers to dial
into, 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' servers as appropriate.
Note: further actions such as viewing the status of daemons or resetting
via daemons(0)
should be carried out with the desired '.compute'
argument specified.
When using dispatcher, calling daemons()
returns a matrix with the
following columns:
'online' shows as 1 when there is an active connection, or else 0 if a server has yet to connect or has disconnected.
'instance' increments by 1 every time there is a new connection at a URL.
When this happens, the 'assigned' and 'complete' statistics reset to zero.
This counter is designed to track new server instances connecting after
previous ones have ended (due to time-outs etc.). 'instance' itself
resets to zero if the URL is regenerated by saisei
.
'assigned' shows the cumulative number of tasks assigned to the server instance by the dispatcher.
'complete' shows the cumulative number of tasks completed by the server instance.
The URLs are stored as row names to the matrix.
Specifying the .timeout
argument in mirai
will ensure
that the 'mirai' always resolves.
However, the task may not have completed and still be ongoing in the
daemon process. In such situations, dispatcher ensures that queued tasks
are not assigned to the busy process, however overall performance may
still be degraded if they remain in use. If a process hangs and cannot be
restarted manually, saisei
specifying force = TRUE
may be used to regenerate any particular URL for a new server
to connect to.
if (interactive()) {
# Only run examples in interactive R sessions
# Create 2 local daemons (using dispatcher)
daemons(2)
# View status
daemons()
# Reset to zero
daemons(0)
# Create 2 local daemons (not using dispatcher)
daemons(2, dispatcher = FALSE)
# View status
daemons()
# Reset to zero
daemons(0)
# 2 remote daemons via dispatcher (using zero wildcard)
daemons(2, url = "ws://:0")
# View status
daemons()
# Reset to zero
daemons(0)
# Set client URL for remote servers to dial into (using zero wildcard)
daemons(url = "tcp://:0", dispatcher = FALSE)
# View status
daemons()
# Reset to zero
daemons(0)
}