[Ironpython-users] IronPython, Daily Digest 8/26/2014

CodePlex no_reply at codeplex.com
Wed Aug 27 09:22:59 CEST 2014


Hi ironpython,

Here's your Daily Digest of new issues for project "IronPython".

In today's digest:ISSUES

1. [New issue] "No module named ..." exception in multi threading environment

----------------------------------------------

ISSUES

1. [New issue] "No module named ..." exception in multi threading environment
http://ironpython.codeplex.com/workitem/35498
User thomasmischke has proposed the issue:

"Hi,

we are using IronPython (2.7.4 and before that 2.6.2) in a heavy multi threading environment. There is just one engine, but many threads that execute the same scripts over and over again.

We found a race condition when adding references to DLLs. A script that runs fine a hundred times sometimes throws the exception "No module named ..." when trying to execute a line like "from ... import *".

We tracked down the problem to the method LoadAssembly in the class ScriptDomainManager. When we extend the "lock" in that method, the problem disappears. Our new method looks like this:
public bool LoadAssembly(Assembly assembly) {
        ContractUtils.RequiresNotNull(assembly, "assembly");

        lock (_loadedAssemblies) {
            if (_loadedAssemblies.Contains(assembly)) {
                // only deliver the event if we've never added the assembly before
                return false;
            }
            _loadedAssemblies.Add(assembly);

            EventHandler<AssemblyLoadedEventArgs> assmLoaded = AssemblyLoaded;
            if (assmLoaded != null) {
                assmLoaded(this, new AssemblyLoadedEventArgs(assembly));
            }
        }

        return true;
    }


The following things seem to be needed to reproduce the problem:

Create a DLL ClassLibrary1 with an empty class Class1.
Create a DLL ClassLibrary2 with an empty class Class2.

Create a script A as follows:
import clr, sys
if not "c:\\VisualStudioProjects\\ClassLibrary1\\ClassLibrary1\\bin\\Debug\\" in sys.path:
   sys.path.append("c:\\VisualStudioProjects\\ClassLibrary1\\ClassLibrary1\\bin\\Debug\\")
clr.AddReferenceToFile("ClassLibrary1.dll")
from ClassLibrary1 import Class1


Create a script B as follows:
import clr, sys
if not "c:\\VisualStudioProjects\\ClassLibrary1\\ClassLibrary2\\bin\\Debug\\" in sys.path:
   sys.path.append("c:\\VisualStudioProjects\\ClassLibrary1\\ClassLibrary2\\bin\\Debug\\")
clr.AddReferenceToFile("ClassLibrary2.dll")
from ClassLibrary2 import Class2


Create a function Main in C# as follows:
static void Main() {
        while (true) {
            ScriptEngine _Engine = Python.CreateEngine();
            ScriptSource source = _Engine.CreateScriptSourceFromFile(@"script1.py");
            ScriptSource source1 = _Engine.CreateScriptSourceFromFile(@"script2.py");
            CompiledCode _Code = source.Compile();
            CompiledCode _Code1 = source1.Compile();

            _Code.Execute(_Engine.CreateScope());

            for (int i = 0; i < 10; i++) {
                Thread t = new Thread(() => {
                    try {
                        _Code1.Execute(_Engine.CreateScope());
                    }
                    catch (Exception ex) {
                        Console.WriteLine(ex.ToString());
                        throw;
                    }
                });
                t.Start();
            }
            Thread.Sleep(1000);
        }
    }


When you run this Main function, depending on your hardware it will take quite a lot of time, until the error occures for the first time. The race condition can be "forced" by adding a sleep in the ScriptDomainManager as follows:
public bool LoadAssembly(Assembly assembly) {
        ContractUtils.RequiresNotNull(assembly, "assembly");

        lock (_loadedAssemblies) {
            if (_loadedAssemblies.Contains(assembly)) {
                // only deliver the event if we've never added the assembly before
                return false;
            }
            _loadedAssemblies.Add(assembly);
        }
        Thread.Sleep(500);
            EventHandler<AssemblyLoadedEventArgs> assmLoaded = AssemblyLoaded;
            if (assmLoaded != null) {
                assmLoaded(this, new AssemblyLoadedEventArgs(assembly));
            }

        return true;
    }


Now it takes normally just a few seconds/runs of the program to trigger the error message.
With the extended lock as written before, this problem does not occur any more.

Initially this issue was reported at GitHub. There I was asked to report it here at codeplex, or fork and ask for a pull request. I do not know the internals of IronPython and the DLR well enough to try the fork solution...

Best regards,

Thomas Mischke"
----------------------------------------------



----------------------------------------------
You are receiving this email because you subscribed to notifications on CodePlex.

To report a bug, request a feature, or add a comment, visit IronPython Issue Tracker. You can unsubscribe or change your issue notification settings on CodePlex.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/ironpython-users/attachments/20140827/b35a8dbd/attachment.html>


More information about the Ironpython-users mailing list