views:

161

answers:

3
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IronPython;
using IronPython.Hosting;

namespace EmbeddedIP2_6
{
    class Program
    {
        static void Main(string[] args)
        {
            var engine = Python.CreateEngine();
            var ss = engine.CreateScriptSourceFromString("B", Microsoft.Scripting.SourceCodeKind.Expression);
            var cc = ss.Compile();
            var timer = System.Diagnostics.Stopwatch.StartNew();
            timer.Start();
            for (int i = 0; i < 10000; i++)
            {
                var scope = engine.CreateScope();
                scope.SetVariable("B", 2);
                var value = cc.Execute(scope);
            }
            timer.Stop();
            System.Console.WriteLine(timer.Elapsed.ToString());
        }
    }
}

I try the above in C# 3.5 using IPY 2.0 and IPY 2.6. I find IPY 2.6 to be more than an order of magnitude slower. This is most probably programmer error. Any help would be appreciated.

A: 

You're doing three things within the loop:

  • Creating a scope
  • Setting a variable within the scope
  • Executing the script

Currently you can't tell which of these has changed in performance terms - possibly all of them. I would suggest you change your code to test this.

Also, have you tried 2.6 within .NET 4.0? I'd be interested to hear what the differences are like with the built-in DLR. Quite possibly no difference at all, but...

Jon Skeet
It is in Execute. In any case, my question is more wrt to the idea that 2.6 is faster and better than 2.0 for embedded apps. The above case seems like a 'hello world' example in that sense.
Yeah, the results of 2.6 running on the DLR would be interesting.
Finglas
@unknown: Yes, it does look like a "hello world" example - have you tried with something which does more within the script? For instance, if the start-up/shutdown of 2.6 has slowed but the execution engine has sped up, that could be significant - or it could be the other way round!
Jon Skeet
Preliminary tests indicate that it might be the other way around. Startup/shutdown is faster. Of course, it just might be that I need some sort of a flag somewhere (I have tried all the ones in ModeleOptions and CompilerOptions).
My previous assertion was wrong. I had an error in my test code. As it turns out, it is actually slower in the 'SetVariable' on the scope. Sorry about that.
Cool - that's something which wouldn't bother me as much as the "engine" itself being slower. Might be worth pinging the team about it though.
Jon Skeet
I tried it in C# 4.0, the behavour is the same (including that of the workaround) as that in C# 3.5
+2  A: 

In IronPython 2.6 the DLR has been updated to use IDynamicMetaObjectProvider as the backing for scope objects instead of the now deprecated IAttributesCollection interface. This lets languages implement their global lookup in such a way that it too benefits from call site caching. For example you could imagine a web browser having an IDMOP which has a "document" property so the languages can quickly lookup that commonly used value.

As a consequence of that though all of the gets/sets go through ObjectOperations which needs to get a binder, get or make a call site, and then invoke via the call site. That's slower than what used to be an interface call to do a dictionary lookup. We can add some fast paths back in for the common case that avoid the call site creation overhead.

Long term you'll be able to use C# dynamic to get/set values in a scope which should give you the very best performance.

Dino Viehland
Thank you Dino. I also saw that you have assigned the issue to yourself. I am going to try this in the beta C# 4.0 to see if things are better. Is your last statement above contingent on a future release of IPY or is it true for the current version when used with the beta C# 4.0?Is there some way to get around this in the 3.5? e.g. implement my own IDynamicMetaObjectProvider...In any case, thanks for your prompt response. Embedded IPY provides a great way to provide full-fledged scripting (and hence user customizations) to applications. I love the combo of C# and IPY.
If by "current version when used with the beta C# 4.0" you mean the IronPython 2.6 CTP for .NET 4.0 Beta 2 then yes. If it's the version of IronPython compiled for .NET 2.0 then it won't work (because the IDMOP implementations won't be the exact same type).
Dino Viehland
Ah! My mistake. Thanks.
A: 

Workaround for above problem:

var scopeProvider = new Microsoft.Scripting.ScopeStorage();
scopeProvider.SetValue("B", true, 2);
var scope = engine.CreateScope(scopeProvider);

This gets rid of the performance overhead with the previous code.