Существуют ли соображения производительности при рефакторинге членов класса в контейнер struct? - PullRequest
2 голосов
/ 28 апреля 2020

Допустим, у меня есть несколько классов, подобных этим:

class MyClassA {
    public List<string> UpData;
    public List<string> DownData;
    public List<string> LeftData;
    public List<string> RightData;
}

class MyClassB {
    public List<string> UpData;
    public List<string> DownData;
    public List<string> LeftData;
    public List<string> RightData;
}

Я бы хотел реорганизовать их, чтобы я мог добавить некоторые удобства (например, Enumerator или наличие некоторых функций, которые позволяют мне выбирать специфику c member):

struct DirectionMap {
    public List<string> Up;
    public List<string> Down;
    public List<string> Left;
    public List<string> Right;
    //... various helper functions ...
}

class MyClassA {
    public DirectionMap Data;
}

class MyClassB {
    public DirectionMap Data;
}

Однако мое приложение требует очень много памяти, и у меня есть миллионы таких экземпляров, поэтому мне нужно помнить об использовании памяти и сборе мусора. Я также должен мутировать эти объекты как можно чаще, поэтому скорость также важна. Есть ли какие-либо издержки производительности при выполнении этого?

Если я правильно понимаю, если бы DirectionMap был классом, он бы использовал немного больше памяти для хранения указателя на него, а затем прикоснулся к куче, правильно? Но это бесплатно как структура?

Я понимаю, что изменяемые объекты в структурах могут вызывать ошибки, но я не планирую когда-либо передавать Data, только списки строк, которые он содержит, которые являются ссылочными значениями.

1 Ответ

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

Первое правило, когда речь идет о производительности, это профилировать код, даже опытные разработчики могут быть удивлены тем, что на это требуется время.

Я бы ожидал, что использование памяти и производительность будут одинаковыми, если вы положите вещи в структура против непосредственно в классе. Расположение памяти должно быть одинаковым или идентичным.

Я бы не советовал менять структуру, если вы не очень осторожны. Т.е. замена содержимого Up-list будет хорошей идеей, но замена Up-list новым списком может вызвать проблемы. См. Почему мутирующие структуры являются злыми .

Если вы реализуете интерфейсы для своей структуры, вам нужно знать о боксе. Если вы реализуете IEnumerable<List<string>> и используете любой метод linq, это приведет к тому, что структура будет в штучной упаковке , что не идеально для производительности. Этого следует избегать, используя общие ограничения c. Вы также можете использовать структуру readonly и модификатор параметра * и 1012 * в , чтобы избежать копирования. Например:

public static void MyMethod<T, U>(in T value) where T : struct, IEnumerable<U>
{
        // do something
}
...