#worker-thread #run-time #actor #function #async

nightly heph-rt

Heph-rt is a speciailised runtime for Heph's actor

2 releases

0.4.1 Oct 14, 2022
0.4.0 Apr 21, 2022

#39 in #worker-thread

MIT license

740KB
13K SLoC

Heph-rt

License: MIT Crates.io Docs

Specialised runtime for Heph actors.

See the main Heph README for more information.


lib.rs:

Specialised runtime for Heph actors.

If this is your introduction to Heph it better to start with the Heph crate first.

The root of the crate has two main types:

  • Runtime is Heph's runtime, used to run all actors.
  • RuntimeRef is a reference to a running runtime, used for example to spawn new actors.

Running Heph's runtime

Building a runtime starts with calling setup, which will create a new Setup builder type, which allows configuration of the Runtime. The new function can also be used, but is really only meant for quick prototyping or testing.

Setup has a number of configuration options. An example of one such option is the number of threads the runtime uses, this can configured with the num_threads and use_all_cores methods. When using use_all_cores the CPU affinity can automatically be set using auto_cpu_affinity.

Once the runtime is fully configured it can be build, which returns the Runtime type.

After the runtime is build it is also possible to start thread-safe actors using Spawn implementation on Runtime or try_spawn. Synchronous actors can be spawned using spawn_sync_actor. Note however that most actors should run as thread-local actors however. To spawn a thread-local actor see the Spawn implementation for RuntimeRef or RuntimeRef::try_spawn_local, which can spawn both thread-safe and thread-local actors. For documentation on the different kind of actors see the actor module.

To help with initialisation and spawning of thread-local actor it's possible to run functions on all worker threads using run_on_workers. This will run the same (cloned) function on all workers threads with access to a RuntimeRef.

Finally after configurating the runtime and spawning actors the runtime can be started, which runs all actors and waits for them to complete.

Examples

This simple example shows how to run a Runtime and add how start a single actor on each thread. This should print "Hello World" twice (once on each worker thread started).

#![feature(never_type)]

use heph::actor;
use heph::supervisor::NoSupervisor;
use heph_rt::spawn::ActorOptions;
use heph_rt::{self as rt, Runtime, RuntimeRef, ThreadLocal};

fn main() -> Result<(), rt::Error> {
    // Build a new `Runtime` with two worker threads.
    let mut runtime = Runtime::setup().num_threads(2).build()?;
    // On each worker thread run our setup function.
    runtime.run_on_workers(setup)?;
    // And start the runtime.
    runtime.start()
}

// This setup function will on run on each created thread. In the case of
// this example we create two threads (see `main`).
fn setup(mut runtime_ref: RuntimeRef) -> Result<(), !> {
    // Asynchronous function don't yet implement the required `NewActor`
    // trait, but function pointers do so we cast our type to a function
    // pointer.
    let actor = actor as fn(_, _) -> _;
    // Each actors needs to be supervised, but since our actor doesn't
    // return an error (the error type is `!`) we can get away with our
    // `NoSupervisor` which doesn't do anything (as it can never be called).
    let supervisor = NoSupervisor;
    // All actors start with one or more arguments, in our case it's message
    // used to greet people with. See `actor` below.
    let arg = "Hello";
    // Spawn the actor to run on our actor runtime. We get an actor reference
    // back which can be used to send the actor messages, see below.
    let actor_ref = runtime_ref.spawn_local(supervisor, actor, arg, ActorOptions::default());

    // Send a message to the actor we just spawned.
    actor_ref.try_send("World").unwrap();

    Ok(())
}

/// Our actor that greets people.
async fn actor(mut ctx: actor::Context<&'static str, ThreadLocal>, msg: &'static str) {
    // `msg` is the argument passed to `spawn` in the `setup` function
    // above, in this example it was "Hello".

    // Using the context we can receive messages send to this actor, so here
    // we'll receive the "World" message we send in the `setup` function.
    if let Ok(name) = ctx.receive_next().await {
        // This should print "Hello world"!
        println!("{} {}", msg, name);
    }
}

For more examples see the examples directory in the source code.

Features

This crate has one optional: test. The test feature will enable the test module which adds testing facilities.

Dependencies

~1–11MB
~69K SLoC