This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
rhaj/rhai_engine/rhaibook/patterns/parallel.md
2025-04-03 09:18:05 +02:00

2.7 KiB

One Engine Instance Per Call

{{#include ../links.md}}


* A system where scripts are called a _lot_, in tight loops or in parallel.

* Keeping a global [`Engine`] instance is sub-optimal due to contention and locking.

* Scripts need to be executed independently from each other, perhaps concurrently.

* Scripts are used to [create Rust closures][`Func`] that are stored and may be called at any time,
  perhaps concurrently. In this case, the [`Engine`] instance is usually moved into the closure itself.

* Rhai's [`AST`] structure is sharable – meaning that one copy of the [`AST`] can be run on
  multiple instances of [`Engine`] simultaneously.

* Rhai's [packages] and [modules] are also sharable.

* This means that [`Engine`] instances can be _decoupled_ from the base system ([packages] and
  [modules]) as well as the scripts ([`AST`]) so they can be created very cheaply.

Procedure

  • Gather up all common custom functions into a [custom package].

    • This [custom package] should also include standard [packages] needed. For example, to duplicate Engine::new, use a StandardPackage.

    • [Packages] are sharable, so using a [custom package] is much cheaper than registering all the functions one by one.

  • Store a global [AST] for use with all [Engine] instances.

  • Always use Engine::new_raw to create a [raw Engine], instead of Engine::new which is much more expensive. A [raw Engine] is extremely cheap to create.

  • Register the [custom package] with the [raw Engine] via Package::register_into_engine.

Examples

use rhai::def_package;
use rhai::packages::{Package, StandardPackage};
use rhai::FuncRegistration;

// Define the custom package 'MyCustomPackage'.
def_package! {
    /// My own personal super-duper custom package
    // Aggregate other base packages simply by listing them after the colon.
    pub MyCustomPackage(module) : StandardPackage {
      // Register additional Rust functions.
      FuncRegistration::new("foo")
          .with_params(&["s: ImmutableString", "i64"])
          .set_into_module(module, |s: ImmutableString| foo(s.into_owned()));
    }
}

let ast = /* ... some AST ... */;

let my_custom_package = MyCustomPackage::new();

// The following loop creates 10,000 Engine instances!

for x in 0..10_000 {
    // Create a raw Engine - extremely cheap
    let mut engine = Engine::new_raw();

    // Register custom package - cheap
    my_custom_package.register_into_engine(&mut engine);

    // Evaluate script
    engine.run_ast(&ast)?;
}