System.Drawing.Point намного быстрее, чем моя простая структура - PullRequest
1 голос
/ 22 апреля 2020

Что такое мастер dry в этом классе System.Drawing.Point, который делает его намного быстрее, чем моя простая структура?

Это немного быстрее. Я получаю 1-5 мс для класса Point и 2000 мс или больше для своей структуры.

Глядя на источник Points.cs , я не достаточно квалифицирован, чтобы определить, что он делает. , Я попытался реализовать IEquatable (возможно, неправильно) и не смог получить никакой выгоды.

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

Ответы [ 2 ]

2 голосов
/ 22 апреля 2020

Это связано с отсутствием переопределения для GetHashCode (вы также должны переопределить Equals), как в источнике Point . Они делают это следующим образом:

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

Если ваша реализация была такой же, вы должны увидеть аналогичную производительность.

1 голос
/ 22 апреля 2020

Хотя struct обеспечивает реализацию по умолчанию для Equals и GetHashCode, они имеют плохую производительность, так как используют отражение. Вместо этого вы должны предоставить свою собственную реализацию. Хотя вам не нужно реализовывать IEquatable<Point>, я думаю, что это стоит:

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

Я сделал случайный тест, используя ваш код, и производительность этого кода похожа на System.Drawing.Point или, возможно, немного медленнее, но не в тысячи раз медленнее, чем наивный подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...