В .Net, когда когда-либо я должен передавать структуры по ссылке для повышения производительности?

В моем приложении С# у меня есть большая структура (176 байт), которая передается потенциально сто тысяч раз в секунду для функции. Затем эта функция просто берет указатель на структуру и передает указатель на неуправляемый код. Ни функция, ни неуправляемый код не вносят никаких изменений в структуру.

Мой вопрос: должен ли я передать структуру функции по значению или по ссылке? В этом конкретном случае я предполагаю, что передача по ссылке будет намного быстрее, чем нажатие 176 байт в стек вызовов, если только JIT не узнает, что структура никогда не изменяется (моя догадка заключается в том, что она не может распознать это, поскольку структура адрес передается неуправляемому коду) и оптимизирует код.

Так как мы на нем, давайте также ответим на более общий случай, когда функция не передает указатель структуры на неуправляемый код, но вместо этого выполняет некоторую операцию только для чтения в содержимом структуры. Будет ли быстрее передавать структуру по ссылке? В этом случае JIT признает, что структура никогда не изменяется и, таким образом, оптимизируется? Предположительно, не более эффективно передавать 1-байтовую структуру по ссылке, но при каком размере структуры становится лучше передавать структуру по ссылке, если когда-либо?

Спасибо.

EDIT:

Как указано ниже, также возможно создать "эквивалентный" класс для регулярного использования, а затем использовать структуру при переходе на неуправляемый код. Здесь я вижу два варианта:

1) Создайте класс "оболочка", который просто содержит структуру, а затем при необходимости свяжет и передаст указатель на структуру неуправляемому коду. Потенциальная проблема, которую я вижу, заключается в том, что фиксация имеет свои собственные последствия.

2) Создайте эквивалентный класс, поля которого копируются в структуру при необходимости структуры. Но копирование займет много времени, и мне кажется, что в первую очередь победить точку передачи по ссылке.

EDIT:

Как уже упоминалось несколько раз, я мог бы точно измерить производительность каждого из этих методов. Я сделаю это и опубликую результаты. Тем не менее, мне все еще интересно видеть ответы и рассуждения людей с интеллектуальной точки зрения.

Ответы

Ответ 1

Я сделал очень неформальное профилирование, и результаты показывают, что для моего конкретного приложения есть небольшое увеличение производительности для передачи по ссылке. Для побочной стоимости я получил около 10 050 000 вызовов в секунду, тогда как для справки я получил около 11 200 000 вызовов в секунду.

Ваш пробег может отличаться.

Ответ 2

Прежде чем вы спросите, следует ли передавать структуру по ссылке, вы должны спросить себя, почему у вас есть такая огромная структура в первую очередь. Нужно ли быть структурой? Если вам нужно использовать struct в какой-то момент для P/Invoke, было бы целесообразно иметь структуру только для этого, а затем эквивалентный класс в другом месте?

Структура, которая очень большая, очень необычная...

См. Руководство по разработке правил для создания библиотек классов в разделе Выбор между классами и Структуры для более подробного руководства по этому вопросу.

Ответ 3

Единственный способ, которым вы можете получить ответ на этот вопрос, - это кодирование обоих параметров и измерение производительности.

Вы указываете неуправляемый/управляемый интерфейс. Мой опыт заключается в том, что для взаимодействия требуется удивительно долгое время. Вы можете попробовать изменить код:

void ManagedMethod(MyStruct[] items) {
  foreach (var item in items) {
    unmanagedHandle.ProcessOne(item);
  }
}

To:

void ManagedMethod(MyStruct[] items) {
  unmanagedHandle.ProcessMany(items, items.Count);
}

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

Ответ 4

Разве это не то, что достойный компилятор должен оптимизировать автоматически, если структура не изменена вызываемым пользователем?

Ответ 5

Почему бы просто не использовать класс вместо этого и передать свой класс вашей функции P/Invoke?

Использование класса будет хорошо передаваться в управляемом коде и будет работать так же, как передача структуры по ссылке на функцию P/Invoke.

например.

// What you have
public struct X
{
   public int data;
}
[DllImport("mylib.dll")]
static extern void Foo( ref X arg);

// What you could do
[StructLayout(LayoutKind.Sequential)]
public class Y
{
    public int data;
}
[DllImport("mylib.dll")]
static extern void Bar( Y arg );