Some features are for performance. In order to squeeze out the maximum performance from Rhai, the following features should be considered:
|support only a single ||reduce data size|
|remove support for floating-point numbers||reduce code size|
|set floating-point numbers (if not disabled) to 32-bit||reduce data size|
|remove support for variables sharing||no need for data locking|
|disable all safety checks||remove checking code|
|disable loading external modules||reduce code size|
|disable position tracking during parsing||reduce data size|
|disable custom syntax||reduce code size|
When the above feature flags are used, performance may increase by around 15-20%.
See Rhai performance benchmarks.
By default, Rhai provides a Don’t Panic guarantee and prevents malicious scripts from bringing down the host. Any panic can be considered a bug.
For operator-heavy scripts, this may provide a substantial speed-up.
If only a single integer type is needed in scripts – most of the time this is the case –
it is best to avoid registering lots of functions related to other integer types that will never be used.
As a result,
Engine creation will be faster because fewer functions need to be loaded.
If only 32-bit integers are needed – again, most of the time this is the case – turn on
Under this feature, only
i32 is supported as a built-in integer type and no others.
On 64-bit targets this may not gain much, but on certain 32-bit targets this improves performance due to 64-bit arithmetic requiring more CPU cycles to complete.
Dynamic needs to be up 12-16 bytes long in order to hold an
Dynamic helps performance due to better cache efficiency.
Internally, Rhai uses immutable strings instead of the Rust
This is mainly to avoid excessive cloning when passing function arguments.
Rhai’s internal string type is
Arc<SmartString> depending on the
sync feature). It is cheap to clone, but expensive to modify
(a new copy of the string must be made in order to change it).
This is because every data access must be checked whether it is a shared value and, if so, take a read lock before reading it.
As the vast majority of variables are not shared, needless to say this is a non-trivial performance overhead.
For embedded scripts that are not expected to cause errors, the
no_position feature can be used
to disable position tracking during parsing.
No line number/character position information is kept for error reporting purposes.
This may result in a slightly fast build due to elimination of code related to position tracking.
Rhai values are typically cloned when passed around, especially into function calls. Large data structures may incur material cloning overhead.
Some functions accept the first parameter as a mutable reference (i.e.
&mut), for example
methods for custom types, and may avoid potentially-costly cloning.
For example, the
+= (append) compound assignment takes a mutable reference to the variable while
+ (add) assignment usually doesn’t. The difference in performance can be huge:
let x = create_some_very_big_and_expensive_type(); x = x + 1; // ^ 'x' is cloned here // The above is equivalent to: let temp_value = x.clone() + 1; x = temp_value; x += 1; // <- 'x' is NOT cloned
However, there are limits to its intelligence, and only simple variable references are optimized.
x = x + 1; // <- this statement... x += 1; // ... is rewritten as this x[y] = x[y] + 1; // <- but this is not, so this is MUCH slower... x[y] += 1; // ... than this some_func(x, 1); // <- this statement... x.some_func(1); // ... is rewritten as this some_func(x[y], 1); // <- but this is not, so 'x[y]` is cloned
This is particularly true for local variables inside a hot loop, where they are created and destroyed in rapid succession.
On 64-bit systems, this limit is raised to 23 ASCII characters, which is almost always adequate.