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/_archive/rhai_engine/rhaibook/patterns/parallel.md
2025-04-04 08:28:07 +02:00

87 lines
2.7 KiB
Markdown

One `Engine` Instance Per Call
==============================
{{#include ../links.md}}
```admonish info "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 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.
```
```admonish abstract "Key concepts"
* 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`]({{rootUrl}}/rust/packages/builtin.md).
* [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
--------
```rust
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)?;
}
```