Reputation: 4939
I'm creating a library for use principally in a non-web environment that makes use of Lua scripts via StackExchange.Redis.
Should we be loading Lua scripts for every Evaluate call when using StackExchange.Redis, like
var prepped = LuaScript.Prepare(_someScript);
var loaded = prepped.Load(someServer);
loaded.Evaluate(someDb);
or should we be loading once and then reusing the LoadedLuaScript instances each time we're going to Evaluate them in a given process?
Upvotes: 3
Views: 1160
Reputation: 188
Can't comment yet, but I just want to add about @ChriZ answer, It does look like LuaScript.Evaluate might use caching by looking at RedisDatabase.cs->GetMessages (didn't check it).. but..
Following the Evaluate code it looks like it does some dirty Hash regex checking (ScriptLoadProcessor.IsSHA1) and lots of other checks that are not very efficient in my opinion...
On top of that, if you go to LuaScript.cs its written explicitly:
Unlike LuaScript, LoadedLuaScript sends the hash of it's ExecutableScript to Redis rather than pass the whole script on each call. This requires that the script be loaded into Redis before it is used. To create a LoadedLuaScript first create a LuaScript via LuaScript.Prepare(string), then call Load(IServer, CommandFlags) on the returned LuaScript.
Please correct me if I'm wrong...
Upvotes: 0
Reputation: 51
For performance reasons Lua scripts can be loaded to redis and then called by their hash. This loading is optional and should be done only once to gain the performance benefit.
With StackExchange.Redis you don't have to explicitly use the Load method. It is easier to let StackExchange.Redis handle the caching. The LuaScript class automatically transmits the Lua script to redis on the first call to 'ScriptEvaluate'. For further calls of the same script only the hash is used:
var prepared = LuaScript.Prepare(script);
prepared.Evaluate(someDb); // loads the script to redis and calls it
var prepared2 = LuaScript.Prepare(script);
prepared2.Evaluate(someDb); // calls the script by it's hash
Upvotes: 1
Reputation: 4939
Scripts should be loaded once, at startup, and keep the LoadedLuaScript instances to Evaluate when needed. StackExchange.Redis doesn't cache the LoadedLuaScripts anywhere, so if you go through the prep and load process on every call then all you'll do is have StackExchange.Redis transfer the script over to Redis, where it'll be hashed, Redis will realise that it already has it, then pass the hash back.
If your processes aren't starting up frequently (for some value of frequently) then it might be reasonable to load all scripts at startup even if they've been loaded in Redis already, as it won't lead to multiple instances of those scripts being cached at Redis. You could keep the LoadedLuaScripts available in a simple cache, like:
private static readonly string _helloScript =
"print(\"Hello World!\")"
;
public void LoadScripts(IDatabase db, IServer srv)
{
var scripts = new Dictionary<string, string>
{
{ "sayHello", _helloScript },
};
foreach (var scriptName in scripts.Keys)
{
var prepped = LuaScript.Prepare(scripts[scriptName]);
_scripts.Add(scriptName, prepped.Load(srv));
}
}
public void SayHello(IDatabase db)
{
_scripts["sayHello"].Evaluate(db);
}
Upvotes: 1