Когда я перестраиваю свою библиотеку c ++ DLL (которую я вызываю из c #) в / CLR (изначально нативный), производительность падает вдвое

Когда вы пишете [x]*3, вы получаете, по существу, список [x, x, x]. То есть список с 3 ссылками на тот же x. Когда вы затем изменяете этот сингл x, он отображается через все три ссылки на него.

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

[[1]*4 for n in range(3)]

, который будет повторно оценивать [1]*4 каждый раз, а не оценивать его один раз и делать 3 ссылки на 1 список.


Вы можете удивиться почему * не может создавать независимые объекты так, как это делает понимание списка. Это потому, что оператор умножения * работает с объектами, не видя выражений. Когда вы используете * для умножения [[1] * 4] на 3, * видит только 1-элементный список [[1] * 4], а не текст выражения [[1] * 4. * не имеет понятия, как делать копии этого элемента, не знаю, как переоценить [[1] * 4], и не подозревайте, что вы даже хотите копировать, и вообще, возможно, даже не было способа скопировать элемент.

Единственный вариант * - это сделать новые ссылки на существующий подсписчик вместо того, чтобы пытаться создавать новые подсписки. Все остальное было бы непоследовательным или требовало бы значительного пересмотра основополагающих решений по языковому дизайну.

Напротив, понимание списка переоценивает выражение элемента на каждой итерации. [[1] * 4 for n in range(3)] пересчитывает [1] * 4 каждый раз по той же причине [x**2 for x in range(3)] каждый раз переоценивает x**2. Каждая оценка [1] * 4 генерирует новый список, поэтому понимание списка делает то, что вы хотели.

Кстати, [1] * 4 также не копирует элементы [1], но это не имеет значения , так как целые числа неизменны. Вы не можете сделать что-то вроде 1.value = 2 и превратить 1 в 2.

1
задан Tomasz 24 March 2019 в 05:04
поделиться

1 ответ

С данным интерфейсом нет никакой пользы для компиляции с / clr вообще. Сделайте отладочный собственный код C ++, щелкнув правой кнопкой мыши основной проект C #> Свойства> вкладка Отладка> отметив флажок «Включить отладку собственного кода». Это включает как управляемые, так и неуправляемые механизмы отладки. Вы не можете пошагово перейти к собственному коду, для выполнения изменения механизма отладки требуется точка останова на функции Calc (). Вы все еще можете предпочесть модульный тест, написанный на нативном C ++, если установка точек останова неудобна.

Еще одна вещь, о которой вам нужно позаботиться, это то, что вы создаете код C ++ с включенными настройками Debug. Вы получили это сейчас, поэтому код кажется в два раза медленнее. Проводите тестирование только с настройками Release build, чтобы убедиться, что оптимизатор включен. Лучше всего включить собственный проект C ++ в решение C #, чтобы вы всегда создавали правильный вариант. И вы должны убедиться, что правильная DLL скопирована в каталог сборки основного проекта C #, обычно это делается с событием после сборки. Этот шаг копирования должен отличаться для конфигураций Debug и Release.

Обратите внимание, что объявления [DllImport] неверны. Тип возврата NewCalc () должен быть IntPtr, поэтому он также работает в 64-битном коде. Perf-тестирование 64-битной сборки кода C ++ - это то, что вы хотите попробовать, это может повысить производительность, если функция Calc () использует математику с плавающей запятой. На самом деле использование / clr может быть полезно для улучшения интерфейса, однако вы должны будете научиться писать код на C ++ / CLI и избегать сборки собственного кода C ++ с /clr.

0
ответ дан Hans Passant 24 March 2019 в 05:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: