27

我在 IronPython 中有一个“脚本类”,我的应用程序中的脚本通过调用其实例上的方法来工作。我需要从多个线程实现调用脚本。正确的方法是什么?

我有多个担忧:

  1. ScriptScope线程安全吗?信息是矛盾的。ScriptScope 的文档说“ScriptScope 不是线程安全的。当多个线程可以访问同一个模块时,主机应该锁定,或者应该为每个线程制作一个副本。” 但是,IronRuby 使用相同的 DLR,@JimmySchementi 说ScriptRuntime、ScriptEngine 和 ScriptScope 都是线程安全的,旨在用于线程之间。具体来说,ScriptScope 使用线程安全的数据存储,因此 ScriptScope 可以在线程之间共享。”

  2. 如果我创建多个ScriptScopes,那将意味着多次执行相同的初始化脚本。假设我运行了 10 个 Python 脚本文件,导入了 5 个程序集,并且总体上执行了相当多的代码来准备好“脚本对象”。有什么方法可以避免为每个线程运行大量相同的代码所花费的时间和内存成本?

  3. 是否使ScriptScope变量线程静态(即应用ThreadStaticAttribute)并为要使用的每个线程执行初始化Task.Run?或者我应该使用TaskScheduler具有并发限制的 a,因为多个范围的成本很高?

总体而言:如何正确实现在多个线程中对不同参数运行相同的脚本?脚本必须同时执行,并且不得因竞争条件而崩溃。

4

3 回答 3

2

1.

如果 ScriptScope 的文档说它不是线程安全的,相信它,或者至少表现得像你相信的那样。@JimmySchementi 可能已经查看了当前的实现,并确定它当前是线程安全的,但这并不能保证它在该类的下一个补丁中的行为方式,更不用说下一个主要版本了。

2.

是的,您需要初始化每个 ScriptScope。我会尽量减少您需要的 ScriptScope 的数量,如何做到这一点取决于您的设置。如果相关线程的主要目的是托管 ScriptScope,那么您应该使用 ThreadPool,每个线程都有一个 ThreadLocal<ScriptScope>。如果这些线程在运行脚本的同时还做其他事情,那么您应该有一个存储 ScriptScopes 的对象池,并且每个线程都可以检查 ScriptScopes,完成工作,然后释放 ScriptScope。

3.

如果你沿着这条路走,更喜欢ThreadLocal而不是 ThreadStatic。

于 2014-08-26T23:00:43.130 回答
1

如果我理解正确的话,这就是你在脚本中的做法。

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

看看那个脚本做了什么,它完全启动了一个相同事物的新线程,具有不同的参数。

您可以看到的 py 文件是否完全线程化,并使用 IronPython。这就是你如何正确地做线程,而不是以任何其他方式。

于 2016-05-13T16:56:08.643 回答
-1

因为,看起来你没有得到一个具体的答案,所以我有一个普遍的答案。

我的一位同事在我之前的工作中使用了 IronPhython,并且处理多线程是必不可少的,所以我可以说在生产系统的多线程环境中运行 IronPython 是可能的。

我不知道他是使用自己的锁定还是依赖 IronPython 内部的锁定。

我建议:

a) 自己运行测试。您应该能够编写一个简单的测试来证明它是否安全。像下面这样粗略的代码可能是一个好的开始:

    [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) 无论如何都要加锁。在您的代码中完成锁定可能不是一个大问题,您将消除不确定性。

最终,如果文档说某些东西不是线程安全的,您将不得不证明它是(测试)或玩安全(您自己的锁定)。无论如何,无论如何都应该在投入生产之前进行多线程测试。我不认为你在开始的时候就真的放松了。

回复 2:再次只是一个建议。创建一个池线程,它会进行一次初始化,然后重用这些线程。

于 2013-07-03T02:40:41.570 回答