2013-05-09 72 views
0

爲了說明這個問題,編譯一個C#項目,引用Microsoft Scripting Runtime和下面的代碼。運行生成的可執行文件的單個實例。在我的12核心機器上,讀取循環持續約180ms。啓動另一個可執行文件的實例會減慢速度,每增加一個可執行文件大約100毫秒。Scripting.Dictionary性能受多個進程影響

任何想法發生了什麼?除了切換到不同的字典實現以外的任何解決方案?

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); 
      } 

     } 
    } 
} 
+1

在控制檯上滾動一千行文本,而計時代碼是一個非常糟糕的主意。 – 2013-05-09 17:47:28

+2

我在1997年寫了'Scripting.Dictionary'。我不知道你的問題是什麼原因,但我會很好奇。不管它是什麼,我都可以向你保證它不太可能被修復。 – 2013-05-09 19:25:22

回答

0

埃裏克,你一定會很高興聽到這個問題是不特定的Scripting.Dictionary,而是與公寓線程模型。可以閱讀關於混合線程模型對MSDN的性能影響,但是對我來說這是一個驚喜(out-of-process)的影響。

我能夠用一種方法創建自己的COM對象,如下所述,替換上例中的Scripting.Dictionary調用。然後,我可以在Test.rgs文件中的'Apartment'和'Both'線程模型之間切換,重建,並確認在啓用MTA的對象中解決了跨進程影響。另外,附加一個調試器並暫停進程,然後使用procexp(來自Microsoft SysInternals),可以看到調用堆棧進入內核,在那裏我假設有一個隊列被管理用於COM編組,造成跨越不同流程的瓶頸。

更糟糕的是,當調用對不同對象的調用時,也會發生這種放緩,這是通過運行一個調用Scripting.Dictionary的應用程序來調用的,其他幾個調用DoNothing()並觀察它們全部變慢。

出於我們的目的,我們將使用替代字典實現(儘管可以更改Scripting.Dictionary線程模型,這似乎是不明智的)。

我想還是有一個關於COM編組的進程間影響的問題。建議必須嘗試避免在多進程環境中使用Apartment線程,除非有人有更好的答案......?

創建測試COM對象

  • Visual Studio創建一個新的項目,使用C++模板ATL(我使用VS 2008)。
  • 選擇服務器類型DLL。
  • 右鍵單擊項目,添加類... - > ATL簡單對象。
  • 給它一個簡短的名字,例如「測試」,確保選擇了公寓線程。
  • 從類視圖中,右鍵單擊界面(ITest)和添加方法...
  • 將方法命名爲「DoNothing」,並保留默認選項。
  • 檢查方法實現是否爲空,然後生成。

現在可以從測試應用程序添加COM引用並調用DoNothing()方法。

+1

感謝您的更新;很高興你想出來了。順便說一句,有一個版本的Scripting.Dictionary錯誤地標記爲Both,而不是Apartment。我的錯。你可以在這裏閱讀有趣的故事:http://blogs.msdn.com/b/ericlippert/archive/2003/09/19/53054.aspx – 2013-05-10 17:08:49