Multi-threading in IronPython
Asked Answered
I

3

27

I have a "script class" in IronPython, and scripting in my app works by calling methods on its instance. I need to implement calling scripts from multiple threads. What is the correct way to do it?

I have multiple concerns:

  1. Is ScriptScope thread-safe? Information is contradictory. ScriptScope's documentation says: "ScriptScope is not thread safe. Host should either lock when multiple threads could access the same module or should make a copy for each thread." However, IronRuby uses the same DLR and @JimmySchementi says that "ScriptRuntime, ScriptEngine, and ScriptScope are all thread safe, designed to be used between threads. Specifically, ScriptScope uses a thread-safe data-store, so ScriptScope can be shared between threads."

  2. If I create multiple ScriptScopes, that would mean executing the same initialization script multiple times. Let's suppose that I run ten Python script files, import five assemblies and on the whole execute quite a bit of code to get the "script object" ready. Is there any way to avoid the time and memory cost of running a lot of the same code for each and every thread?

  3. Is making the ScriptScope variable thread-static (that is, applying ThreadStaticAttribute) and executing initialization for every thread which is utilized by Task.Run the way to go? Or should I use a TaskScheduler with a limit on concurrency, because the cost of multiple scopes is high?

On the whole: how to correctly implement running the same script on different arguments in multiple threads? Scripts must be executing simultaneously and must not crash due to race conditions.

Iconoclasm answered 8/6, 2013 at 12:34 Comment(1)
I feel for you. I found the documentation on both ironpython and ironruby lacking in every aspect since Microsoft stopped officially supporting it.Pericarp
U
2

1.

If the documentation of ScriptScope says it is not thread safe, believe it, or at least act like you believe it. @JimmySchementi may have looked at the current implementation and worked out that it is currently thread safe, but this give no guarantees about how it will behave in the next patch of the class, let alone the next major release.

2.

Yes you will need to initialise each of your ScriptScopes. I would try and minimise the number of ScriptScopes you require, how to do this will depend on your set up. If the main purpose of the threads concerned is to host a ScriptScope then you should use a ThreadPool with each thread having one ThreadLocal<ScriptScope>. If these threads are doing other things as well as running scripts then you should have an Object pool storing the ScriptScopes and each thread can checkout the ScriptScopes, do the work, then release the ScriptScope.

3.

Prefer ThreadLocal over ThreadStatic if you go down this path.

User answered 26/8, 2014 at 23:0 Comment(0)
K
1

This is how you do It in scripts, If I understood you correctly.

https://github.com/dretax/Python-Plugins/blob/master/PlutonPlugins/PluIRC/PluIRC.py#L154

See what that script does, It completely launches a new thread of the same thing, with different arguments.

The py file you can see if FULLY threaded, and uses IronPython. That is HOW you correctly do threads, and NOT in any other way.

Konopka answered 13/5, 2016 at 16:56 Comment(0)
C
-1

Since, it doesn't look like you are getting a concrete answer I have a general one.

A colleague of mine used IronPhython in my previous job and handling multithreading would have been essential, so I can say that it is possible to run IronPython in a multithreaded environment on a production system.

I don't know if he used his own locking or depended on the locking inside IronPython.

I'd suggest:

a) Run tests yourself. You should be able to write a simple test to prove if it's safe or not. Something as crude as the following code could be a good start:

    [Test]
    public void TwoThreadsWithTheirOwnContexts() {
        //Create two threads
        var tasks = new Task[2];
        tasks[0] = Task.Factory.StartNew(PrintSomethingInIronPython1);
        tasks[1] = Task.Factory.StartNew(PrintSomethingInIronPython2);
        Task.WaitAll(tasks);
    }

b) Add locks anyway. It may not be a big issue to have locking done in your code and you will remove the uncertainty.

Ultimately if the docs say something is not thread-safe you will have to either prove it is (test) or play safe (your own locking). No matter what, having multithreaded tests should be done before you go into production anyway. I don't think you really loose any time by doing them at the beginning.

Re 2: Again a suggestion only. Create a pool threads which do initialization once and then reuse these threads.

Chevaldefrise answered 3/7, 2013 at 2:40 Comment(1)
@JeffreyZhao Agree - thread-safety is an intrinsic quality of something, not a unit testcase.Sightless

© 2022 - 2024 — McMap. All rights reserved.