On Wed, Aug 14, 2002 at 10:35:14AM -0700, Shankar Unni wrote:
> Pat wrote:
> > Just to clarify, the interpreter is (to the best of our knowledge)
> > thread safe. In your case the issue is at the application level -
> > with multiple clients competing to set the same variable without any
> > synchronization.
> There is also the issue of efficiency. When bsh is used in a situation
> where hundreds of such little expressions have to be evaluated every
> second, it helps to be able to save the parse overhead when the
> expressions themselves are changed only very rarely.
If I understand your question correctly then I think wrapping your code in
a method is all that is required - When the method body text is parsed (which
happens only once) it is is stored in the interpreter. Each subsequent method
*invocation* just executes the "compiled" parsed tree again - it does not require
parsing the method text. Also each method invocation is (not withstanding
anything you do at the application level) thread safe - so you can call that
method concurrently in many threads... again not withstanding you doing application
level stuff that requires synchronization.
> For instance, one thing I'm doing in my system (or am in the process of
> implementing, anyway) is to maintain a "pool" of interpreters, each in
> their own Thread, so that these evaluation tasks can be farmed off in
> parallel. This is basically an event processing system, with several
> filters and policies that have to be executed for each event that
> arrives, and they tend to arrive in bursts.
This is a valid alternative... If nothing else it's probably more robust with
respect to us finding bugs in the interpreter in the future, (memory leaks,
concurrency bugs, etc.) But there is no known technical reason you'd have to
do this.. you should be able to work concurrently in one Interpreter.
> Do parsed method bodies survive across multiple Interpreter instances?
If you mean across multiple method invocations in the same interpreter - then
yes. If you mean are they shared among many new instances of interpreters then no.
(but see below about serialization)
Again, as far as I know it should be possible to arrange any kind of work to be
done in either a single or multiple interpreter scenario... Only synchronization
issues relating to "global" variables (convenience of architecting your scripts)
should really lead you to a need for multiple interpreters or pools...
> How would wrapping the expressions in a method help here? I'd still have
> to make thousands of methods (i.e. every expression and every policy
> body wrapped as a method in each Interpreter instance), or do some
> fairly complicated affinity matching of expressions to interpreter
> instances that would make the pool quite sub-optimal.
Ah, but I thought you had a relatively fixed set of expressions - If your
expressions are really more unique then you do end up parsing them each time.
In which case you could still work in a single VM by passing your script into
a method and using an eval() in the scripted method. The only advantage would
be that you wouldn't have to keep the pool... The performance would probably
be the same because currently BeanShell creates a (very light weight) interpreter
internally for each eval no matter how you do it.
> It really *would* help if we could not only generate a parse tree and
> save that, but also annotate the tree with things like evaluation hints.
> For instance, when you see "event.property", the code tries to look up
> the property as a field, then tries to look for a method called
> "getProperty()". For assignments, it's even more painful, as it has to
> look for a method called "setProperty(...)" and select between
> overloaded variants.
An interesting topic -
The basic groundwork for something like this (at least as far as variables and
class names) *has been there for a while. You'll notice that there is a Name
construct that abstracts this resoluation... The path to these would allow them
to be cached per namespace, so that they could avoid subsequent searches unless
notified of something like a namespace or classloader change. This may turn out
to be a very easy and high return performance tweak - but my original estimates
didn't see this as being a real bottleneck.
There is a lot of room for future optimization in BeanShell.
> Also, if there was then a way to dissociate these parse trees from the
> Interpreter instances, and later load them into any available instance
> quickly, that would allow the system to "warm up" and run substantially
> more effectively in the future.
You can serialize bsh This references containing all of the parsed method code
and load them into another interpreter instance... I'm not sure how much time
this would save, but it's an option.