【问题标题】:Finding results in a Enumerable object quickly在 Enumerable 对象中快速查找结果
【发布时间】:2011-01-22 10:32:09
【问题描述】:

我正在尝试编写一个实用程序来查看自我存储在数据库中的日期以来用户是否已登录到 Windows。

private void bwFindDates_DoWork(object sender, DoWorkEventArgs e)
{
    UserPrincipal u = new UserPrincipal(context);
    u.SamAccountName = "WebLogin*";
    PrincipalSearcher ps = new PrincipalSearcher(u);
    var result = ps.FindAll();
    foreach (WebAccess.WebLoginUsersRow usr in webAccess.WebLoginUsers)
    {
        UserPrincipal b = (UserPrincipal)result.
            Single((a) => a.SamAccountName == usr.WEBUSER);
        if (b.LastLogon.HasValue)
        {
            if (b.LastLogon.Value < usr.MODIFYDATE)
                usr.LastLogin = "Never";
            else
                usr.LastLogin = b.LastLogon.Value.ToShortDateString();
        }
        else
        {
            usr.LastLogin = "Never";
        }
    }
}

但是性能很慢。我从中提取的用户列表有大约 150 个 Windows 用户,所以当我点击UserPrincipal b = (UserPrincipal)result.Single((a) =&gt; a.SamAccountName == usr.CONVUSER); 时,每个用户需要 10 到 15 秒才能完成(单步执行我可以看到它正在执行步骤 a.SamAccountName == usr.CONVUSE 运行对于每个人,所以最坏的情况是运行 O(n^2) 次)

对提高效率的方法有什么建议吗?

【问题讨论】:

  • 我讨厌 SO somtimes 喜欢处理代码部分中的选项卡,有时却不喜欢。

标签: c# linq optimization search


【解决方案1】:

我建议:

var result = ps.FindAll().ToList();

由于PrincipalSearchResult 不像其他东西那样缓存,这将使您的性能水平接近 O(n)。

【讨论】:

    【解决方案2】:

    令人惊讶的是,Single() 在如此小的列表中却花费了如此长的时间。我必须相信这里正在发生其他事情。对ps.FindAll() 的调用可能会返回一个不缓存其结果的对象,并迫使您在Single() 内的每次迭代中对某些资源进行昂贵的调用。

    您可能希望使用分析器来调查当您到达那条线时时间的去向。我还建议查看 FIndAll() 的实现,因为它返回的东西迭代起来异常昂贵。

    因此,在仔细阅读您的代码之后,Single() 如此昂贵是有道理的。 PrincipalSearcher 类使用目录服务存储作为要搜索的存储库。 它不会缓存这些结果。这就是影响你表现的因素。

    您可能希望使用ToList()ToDictionary() 实现列表,以便在本地访问主体信息。

    您也可以完全避免这种代码,而改用FindOne() 方法,这样您就可以直接查询所需的主体。

    但如果你不能使用它,那么这样的东西应该会更好:

    result.ToDictionary(u => u.SamAccountName)[usr.WEBUSER]
    

    【讨论】:

      【解决方案3】:
      var userMap = result.ToDictionary(u => u.SamAccountName);
      
      foreach (WebAccess.WebLoginUsersRow usr in webAccess.WebLoginUsers)
      {
          UserPrincipal b = userMap[usr.WEBUSER];
      
          // ...
      }
      

      【讨论】:

      • 请注意,我使用了ToDictionary,因为您使用Single 意味着您希望每个WebLoginUsersRow 都有一个匹配项。根据需要进行调整。
      • 谢谢。第一次进入大约 15 秒,其余时间为瞬时。
      猜你喜欢
      • 1970-01-01
      • 2014-07-15
      • 2014-06-23
      • 1970-01-01
      • 2012-07-18
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 2011-04-09
      相关资源
      最近更新 更多