Quick search of results in an enumerated object

I am trying to write a utility to find out if a user has logged into windows from the date that I saved in the database.

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

However, performance is very slow. The list of users I'm logging out of has about 150 Windows users, so when I click the line UserPrincipal b = (UserPrincipal)result.Single((a) => a.SamAccountName == usr.CONVUSER); , it takes 10-15 seconds to complete it (step by step I see that step a.SamAccountName == usr.CONVUSE for each person, so the worst case works O (n ^ 2) times)

Any recommendations on how to increase efficiency?

+4
source share
3 answers

Surprisingly, Single() should take quite some time in such a small list. I have to believe that something else is happening here. A call to ps.FindAll() can return an object that does not cache it, and forces you to make an expensive call to some resource at each iteration in Single() .

You might want to use the profiler to investigate where the time goes when you click this line. I would also like to take a look at the implementation of FIndAll() because it was returning something unusually expensive for iteration.

So, after reading your code a little closer, it makes sense why Single() so expensive. The PrincipalSearcher class uses the directory service store as a store for search. It does not cache these results . It affects your performance.

You probably want to materialize the list using ToList() or ToDictionary() so that the main information is accessed locally.

You can also completely eliminate this type of code and use FindOne() instead, which allows you to directly query what you want.

But if you can't use this, then something like this should work better:

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

I would suggest:

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

Since PrincipalSearchResult does not cache, like other things, this will lead you to an O (n) performance level.

+4
source
 var userMap = result.ToDictionary(u => u.SamAccountName); foreach (WebAccess.WebLoginUsersRow usr in webAccess.WebLoginUsers) { UserPrincipal b = userMap[usr.WEBUSER]; // ... } 
+3
source

Source: https://habr.com/ru/post/1302788/


All Articles