Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enumerating via interface - performance loss

I had a little dispute (which was very close to holy war:) ) with my colleage, about the performance of access to list via indeces VS via enumerator. To operate with some facts, I wrote the following test:

   static void Main(string[] args)
    {
        const int count = 10000000;

        var stopwatch = new Stopwatch();

        var list = new List<int>(count);

        var rnd = new Random();

        for (int i = 0; i < count; i++)
        {
            list.Add( rnd.Next());
        }

        const int repeat = 20;

        double indeces = 0;
        double forEach = 0;

        for (int iteration = 0; iteration < repeat; iteration++)
        {
            stopwatch.Restart();
            long tmp = 0;
            for (int i = 0; i < count; i++)
            {                    
                tmp += list[i];
            }

            indeces += stopwatch.Elapsed.TotalSeconds;
            stopwatch.Restart();
            foreach (var integer in list)
            {            
                tmp += integer;
            }

            forEach += stopwatch.Elapsed.TotalSeconds;
        }

        Console.WriteLine(indeces /repeat);
        Console.WriteLine(forEach /repeat);

    }

Actually, it just accesses the elements.

As I expected, index access was faster. This are the results of Release build on my machine:

    0.0347//index access
    0.0737//enumerating

However, I decided to change test a little:

        //the same as before
        ...
        IEnumerable<int> listAsEnumerable = list;
        //the same as before
        ...
        foreach (var integer in listAsEnumerable)
        {                
            tmp += integer;
        }
        ...

And now output was following:

    0.0321//index access
    0.1246//enumerating (2x slower!)

If we are enumerating the same list via interface, the performance is 2 times slower!

Why does this* happening?

this means "enumerating via interface 2 times slower than enumerating the actual list".

My guess is that runtime is using different Enumerators: the list's in first test and a generic one in the second test.

like image 850
undefined Avatar asked May 17 '12 11:05

undefined


People also ask

Is User enumeration bad?

Dangers of Username Enumeration Although username enumeration is not itself always a high risk issue, it does provide an attacker valuable information for other attacks.

What is an enumeration vulnerability?

Written By Matt Mathur. Account enumeration is a common vulnerability that allows an attacker who has acquired a list of valid usernames, IDs, or email addresses to verify whether or not a user exists in a system.

How can companies protect themselves against enumeration attempts?

Use CAPTCHA on all forms - CAPTCHAs are not as effective as MFA but they do effectively block automated enumeration attacks. Limit login attempts - CAPTCHAS and MFA inconvenience cyberattacks by adding latency to each login attempt.

What is the difference between scanning and enumeration?

The Scanning stage only helps to identify the vulnerabilities to a certain extent, but Enumeration helps us learn the complete details such as users, groups and even system level details – routing tables. This phase of the Ethical hacking is to gain end-to-end knowledge of what will be tested in the target environment.


1 Answers

When using List<T>, the foreach doesn't actually use the IEnumerable<T> interface; rather, it uses List<T>.Enumerator, which is a struct. At the trivial level, this means slightly less indirection - not having to de-reference, and using static calls rather than virtual calls - and a more direct implementation.

These differences are very very small, and in any sensible real-life example the difference is noise. However, it may be marginally noticeable if testing just the foreach performance.

To expand on this: foreach doesn't actually require IEnumerable[<T>] - it can work purely on the GetEnumerator() / .MoveNext() / .Current / .Dispose() pattern; this was especially important before generics in 2.0.

However, this is only possible when the variable is typed as List<T> (which has a custom GetEnumerator() method). Once you have IEnumerable<T>, it has to use IEnumerator<T>

like image 66
Marc Gravell Avatar answered Oct 06 '22 00:10

Marc Gravell