脚本.字典性能在多个进程中受到影响

本文关键字:进程 受到影响 字典 性能 脚本 | 更新日期: 2023-09-27 18:12:48

为了说明这个问题,编译一个引用Microsoft Scripting Runtime的c#项目,以及下面的代码。运行结果可执行文件的单个实例。在我的12核机器上,读取循环始终花费大约180ms。启动可执行文件的另一个实例会减慢这一速度,每个额外的可执行文件大约减少100毫秒。

知道是怎么回事吗?除了切换到不同的字典实现之外,还有其他解决方案吗?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch stp = new System.Diagnostics.Stopwatch();
            var dict = (Scripting.IDictionary)(new Scripting.Dictionary());
            stp.Start();
            for (int i = 1; i < 1000; ++i)
            {
                Object s = i.ToString();
                dict.Add(ref s, ref s);
            }
            Console.WriteLine("After Add {0}", stp.ElapsedMilliseconds);
            object q = null;
            for (int j = 0; j < 1000; ++j)
            {
                long old = stp.ElapsedMilliseconds;
                for (int i = 1; i < 10000; ++i)
                {
                    q = null;
                    object s = i.ToString() as object;
                    q = dict.get_Item(ref s);
                }
                long newval = stp.ElapsedMilliseconds;
                Console.WriteLine("After Retrieve {0}", newval - old);
            }
        }
    }
}

脚本.字典性能在多个进程中受到影响

Eric,你会很高兴听到这个问题不是脚本所特有的。字典,而不是使用Apartment线程模型。人们可以在MSDN上读到关于混合线程模型对性能的影响,但是(对我来说)令人惊讶的是进程外的影响。

我能够用一个方法创建我自己的COM对象,如下所述,取代脚本。上面示例中的Dictionary调用。然后我可以在测试中切换"公寓"answers"两者"线程模型。rgs文件,重新构建,并确认在启用mta的对象中解决了跨进程影响。

此外,附加一个调试器并暂停进程,然后使用procexp(来自Microsoft SysInternals),可以看到调用堆栈进入内核,我假设有一个队列正在管理COM编组,导致不同进程之间的瓶颈。

更糟糕的是,当编组对不同对象的调用时也会出现这种减速,这可以通过运行一个调用脚本的应用程序来观察到。字典,几个人调用DoNothing(),然后看着他们慢下来。

出于我们的目的,我们将使用另一种字典实现(尽管可以更改脚本)。字典线程模型,这似乎不明智)。

我想COM编组的进程间影响仍然是一个悬而未决的问题。建议必须尽量避免在多进程环境中使用公寓线程,除非有人有更好的答案…?

创建测试COM对象

  • 在Visual Studio中创建一个新项目,使用c++ ATL模板(我使用的是VS 2008)。
  • 选择服务器类型DLL
  • 右键单击项目,添加类…-> ATL简单对象。
  • 给它一个简短的名字,例如:"测试",确保公寓线程被选中。
  • 在类视图中,右键单击接口(ITest),添加方法…
  • 方法名称,例如:" dononothing ",并保留默认选项。
  • 检查方法实现是否为空,然后构建。

现在可以从测试应用程序中添加COM引用并调用DoNothing()方法。