rhai/doc/src/patterns/parallel.md
2020-12-22 23:45:14 +08:00

2.3 KiB

One Engine Instance Per Call

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

Usage Scenario

  • 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 closure][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.

Key Concepts

  • Create a single instance of each standard [package] required. To duplicate Engine::new, create a StandardPackage.

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

  • Store a global AST for use with all engines.

  • 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.

    Registering the StandardPackage into a [raw Engine] via Engine::register_global_module is essentially the same as Engine::new.

    However, because packages are shared, using existing package is much cheaper than registering all the functions one by one.

  • Register the required packages with the [raw Engine] via Engine::register_global_module, using Package::as_shared_module to obtain a shared [module].

Examples

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

let ast = /* ... some AST ... */;
let std_pkg = StandardPackage::new();
let custom_pkg = MyCustomPackage::new();

let make_call = |x: i64| -> Result<(), Box<EvalAltResult>> {
    // Create a raw Engine - extremely cheap
    let mut engine = Engine::new_raw();

    // Register packages as global modules - cheap
    engine.register_global_module(std_pkg.as_shared_module());
    engine.register_global_module(custom_pkg.as_shared_module());

    // Create custom scope - cheap
    let mut scope = Scope::new();

    // Push variable into scope - relatively cheap
    scope.push("x", x);

    // Evaluate script.
    engine.consume_ast_with_scope(&mut scope, &ast)
};

// The following loop creates 10,000 Engine instances!
for x in 0..10_000 {
    make_call(x)?;
}