One Engine
Instance Per Call
* 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 aStandardPackage
. -
Packages are sharable, so using a custom package is much cheaper than registering all the functions one by one.
-
-
Always use
Engine::new_raw
to create a rawEngine
, instead ofEngine::new
which is much more expensive. A rawEngine
is extremely cheap to create. -
Register the custom package with the raw
Engine
viaEngine::register_global_module
, usingPackage::as_shared_module
to obtain a shared module.
Examples
use rhai::def_package;
use rhai::packages::{Package, StandardPackage};
// Define the custom package 'MyCustomPackage'.
def_package! {
/// My own personal super-duper custom package
pub MyCustomPackage(module) {
// Aggregate other packages simply by calling 'init' on each.
StandardPackage::init(module);
// Register additional Rust functions using 'Module::set_native_fn'.
let hash = module.set_native_fn("foo", |s: ImmutableString| {
Ok(foo(s.into_owned()))
});
// Remember to update the parameter names/types and return type metadata
// when using the 'metadata' feature.
// 'Module::set_native_fn' by default does not set function metadata.
module.update_fn_metadata(hash, &["s: ImmutableString", "i64"]);
}
}
let ast = /* ... some AST ... */;
let custom_pkg = 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
engine.register_global_module(custom_pkg.as_shared_module());
// Evaluate script
engine.run_ast(&ast)?;
}