2012-06-01 43 views
0

我编写了一个C#应用程序,该应用程序对索引编制索引并对该索引执行布尔文本检索算法。文章结尾处的类展示了两者的实现,构建索引并在其上执行算法。重新执行的大量差异

的代码是通过下列方式一个GUI按钮叫:

private void Execute_Click(object sender, EventArgs e) 
    { 
     Stopwatch s; 
     String output = "-----------------------\r\n"; 

     String sr = algoChoice.SelectedItem != null ? algoChoice.SelectedItem.ToString() : ""; 

     switch(sr){ 
      case "Naive search": 
       output += "Naive search\r\n"; 
       algo = NaiveSearch.GetInstance(); 
       break; 
      case "Boolean retrieval": 
       output += "boolean retrieval\r\n"; 
       algo = BooleanRetrieval.GetInstance(); 
       break; 
      default: 
       outputTextbox.Text = outputTextbox.Text + "Choose retrieval-algorithm!\r\n"; 
       return; 
     } 
     output += algo.BuildIndex("../../DocumentCollection/PilzFuehrer.txt") + "\r\n"; 

     postIndexMemory = GC.GetTotalMemory(true); 

     s = Stopwatch.StartNew(); 
     output += algo.Start("../../DocumentCollection/PilzFuehrer.txt", new String[] { "Pilz", "blau", "giftig", "Pilze" }); 
     s.Stop(); 

     postQueryMemory = GC.GetTotalMemory(true); 
     output += "\r\nTime elapsed:" + s.ElapsedTicks/(double)Stopwatch.Frequency + "\r\n"; 

     outputTextbox.Text = output + outputTextbox.Text; 
    } 

开始的第一次执行(...)运行约700μS,每次重播只需要<为10μs。 该应用程序使用Visual Studio 2010和默认的“Debug”build配置进行编译。

我试了很多找到包括分析和不同实现的原因,但效果始终保持不变。

如果有人可以给我一些新的想法,我会尝试甚至解释,我会很生气。

class BooleanRetrieval:RetrievalAlgorithm 
    { 
     protected static RetrievalAlgorithm theInstance; 

     List<String> documentCollection; 
     Dictionary<String, BitArray> index; 

     private BooleanRetrieval() 
      : base("BooleanRetrieval") 
     { 

     } 

     public override String BuildIndex(string filepath) 
     { 
      documentCollection = new List<string>(); 
      index = new Dictionary<string, BitArray>(); 

      documentCollection.Add(filepath); 

      for(int i=0; i<documentCollection.Count; ++i) 
      { 
       StreamReader input = new StreamReader(documentCollection[i]); 

       var text = Regex.Split(input.ReadToEnd(), @"\W+").Distinct().ToArray(); 

       foreach (String wordToIndex in text) 
       { 
        if (!index.ContainsKey(wordToIndex)) 
        { 
         index.Add(wordToIndex, new BitArray(documentCollection.Count, false)); 
        } 

        index[wordToIndex][i] = true; 
       } 
      } 

      return "Index " + index.Keys.Count + "words.";    
     } 

     public override String Start(String filepath, String[] search) 
     { 
      BitArray tempDecision = new BitArray(documentCollection.Count, true); 

      List<String> res = new List<string>(); 

      foreach(String searchWord in search) 
      { 

       if (!index.ContainsKey(searchWord)) 
        return "No documents found!"; 

       tempDecision.And(index[searchWord]); 
      } 


      for (int i = 0; i < tempDecision.Count; ++i) 
      { 
       if (tempDecision[i] == true) 
       { 
        res.Add(documentCollection[i]); 
       } 
      } 

      return res.Count>0 ? res[0]: "Empty!"; 
     } 

     public static RetrievalAlgorithm GetInstance() 
     { 
      Contract.Ensures(Contract.Result<RetrievalAlgorithm>() != null, "result is null."); 
      if (theInstance == null) 
       theInstance = new BooleanRetrieval(); 

      theInstance.Executions++; 
      return theInstance; 
     } 
    } 
+0

http://en.wikipedia.org/wiki/Just-in-time_compilation –

+0

看起来像JIT编译开销。 – ChaosPandion

+0

是的,似乎是正确的想法:System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(algo.GetType()。GetMethod(“Start”)。MethodHandle);将问题减少到因子2. – B1ANCHi

回答

1

.Net应用程序的冷/热启动通常受JIT时间和加载程序集的磁盘访问时间的影响。

对于执行大量磁盘IO的应用程序,首先访问磁盘上的数据将比由于缓存内容(也适用于程序集加载)对同一数据重新运行要慢得多,如果数据足够小适合磁盘的内存缓存。

  • 该任务的第一次运行将受磁盘IO对程序集和数据以及JIT时间的影响。
  • 无需重新启动应用程序即可执行同一任务的第二次运行 - 只需从OS内存缓存中读取数据即可。
  • 第二次运行应用程序 - 再次从操作系统内存缓存和JIT中读取程序集。
+0

我不认为磁盘IO在我的情况下是问题,因为访问索引文件不包括在测量时间中。但JIT似乎解释了很多。谢谢。 – B1ANCHi