简体   繁体   中英

System.Drawing.Point is much faster than my simple struct

What wizardry is in that System.Drawing.Point class that makes it so much faster than my simple struct?

It's quite a bit faster. I'm getting 1-5ms on Point class and 2000ms or more on my struct.

Looking at the Points.cs source , I'm not skilled enough to spot what is doing it. I made an attempt at implementing IEquatable (probably incorrectly) and couldn't make any gains.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;

class Program
{
    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();

        int elementsInSets = 10000;
        int lookupCount = 10000;

        // Point struct from System.Drawing
        HashSet<Point> myPoints = new HashSet<Point>();
        for (int i = 0; i < elementsInSets; i++)
        {
            myPoints.Add(new Point(i, i));
        }

        // My simple struct
        HashSet<P> myPoints2 = new HashSet<P>();
        for (int i = 0; i < elementsInSets; i++)
        {
            myPoints2.Add(new P(i, i));
        }


        sw.Start();
        for (int j = 0; j < lookupCount; j++)
        {
            if (myPoints2.Contains(new P(j, j)))
            {
                //found
            }
        }
        Console.WriteLine("simple P  " + sw.ElapsedMilliseconds + "ms");

        sw.Restart();
        for (int j = 0; j < lookupCount; j++)
        {
            if (myPoints.Contains(new Point(j, j)))
            {
                // found
            }
        }
        Console.WriteLine("Point " + sw.ElapsedMilliseconds + "ms");     
    }
}
public struct P
{
    int x;
    int y;
    public P(int xCoord, int yCoord)
    {
        x = xCoord;
        y = yCoord;
    }
}

That's due to no override for GetHashCode (you should also override Equals ) as in the Point source . They do it this way:

public override bool Equals(object obj) {
    if (!(obj is Point)) return false;
    Point comp = (Point)obj;
    // Note value types can't have derived classes, so we don't need 
    // to check the types of the objects here.  -- Microsoft, 2/21/2001
    return comp.X == this.X && comp.Y == this.Y;
}

public override int GetHashCode() {
    return unchecked(x ^ y);
}

If your implementation was the same you should see similar performance.

While a struct provides a default implementation for Equals and GetHashCode they have bad performance as they use reflection. Instead you should provide your own implementation. While you don't have to implement IEquatable<Point> I think it's worthwhile:

readonly struct Point : IEquatable<Point>
{
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    public int X { get; }
    public int Y { get; }

    public bool Equals(Point other) => X == other.X && Y == other.Y;

    public override bool Equals(object obj) => obj is Point point && Equals(point);

    public override int GetHashCode() => HashCode.Combine(X, Y);
}

I did a casual benchmark using your code and the performance of this code is similar to System.Drawing.Point or perhaps slightly slower but not thousands of times slower like the naïve approach.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM