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

C# 脚本。字典性能在多个进程中受到影响,c#,dictionary,C#,Dictionary,为了说明这个问题,请编译一个C#项目,并引用Microsoft脚本运行时和下面的代码。运行结果可执行文件的单个实例。在我的12核机器上,读取循环持续大约需要180毫秒。启动可执行文件的另一个实例会降低速度,每增加一个可执行文件大约会降低100毫秒 知道发生了什么事吗?除了切换到不同的字典实现,还有其他解决方案吗 using System; using System.Collections.Generic; using System.Linq; using System.Text; namesp

为了说明这个问题,请编译一个C#项目,并引用Microsoft脚本运行时和下面的代码。运行结果可执行文件的单个实例。在我的12核机器上,读取循环持续大约需要180毫秒。启动可执行文件的另一个实例会降低速度,每增加一个可执行文件大约会降低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);
            }

        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
命名空间控制台应用程序4
{
班级计划
{
静态void Main(字符串[]参数)
{
System.Diagnostics.Stopwatch stp=新的System.Diagnostics.Stopwatch();
var dict=(Scripting.IDictionary)(new Scripting.Dictionary());
stp.Start();
对于(int i=1;i<1000;++i)
{
对象s=i.ToString();
添加指令(参考s,参考s);
}
WriteLine(“在Add{0}之后”,stp.elapsedmillisons);
对象q=null;
对于(int j=0;j<1000;++j)
{
long old=stp.elapsedmill秒;
对于(int i=1;i<10000;++i)
{
q=零;
对象s=i.ToString()作为对象;
q=直接获取项目(参考s);
}
long newval=stp.elapsedmillistes;
WriteLine(“在检索{0}之后”,newval-old);
}
}
}
}

Eric,您会很高兴听到这个问题不是特定于Scripting.Dictionary,而是公寓线程模型。您可以阅读混合线程模型对性能的影响,但是(对我来说)令人惊讶的是进程外影响

我能够用一个方法创建自己的COM对象,如下所述,替换上面示例中的Scripting.Dictionary调用。然后,我可以在Test.rgs文件中的“单元”和“两个”线程模型之间切换、重建,并确认跨进程影响已在启用MTA的对象中得到解决

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

更糟糕的是,当编组对不同对象的调用时也会出现这种减速,这可以通过运行一个调用Scripting.Dictionary的应用程序,以及其他几个调用DoNothing()的应用程序来观察,并观察它们的减速情况

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

我想,关于COM编组的进程间影响,还有一个问题尚未解决。建议在多进程环境中尽量避免单元线程,除非有人有更好的答案

创建测试COM对象

    在VisualStudio中使用C++ ATL模板创建新项目(我使用VS 2008)。
  • 选择服务器类型DLL
  • 右键单击项目,添加类…->ATL简单对象
  • 给它一个简短的名称,例如“Test”,确保选择了单元线程
  • 在类视图中,右键单击接口(ITest),然后添加方法
  • 命名方法,例如“DoNothing”,并保留默认选项
  • 检查方法实现是否为空,然后生成

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

在控制台上滚动上千行文本,而计时代码是一个非常糟糕的主意。我在1997年编写了
Scripting.Dictionary
。我不知道你问题的原因是什么,但我很想知道。不管它是什么,我可以向你保证,它不太可能被修复;很高兴你明白了。顺便提一下,有一个版本的Scripting.Dictionary被错误地标记为两者,而不是单元。我的错误。你可以在这里读到有趣的故事: