Фон
У меня есть клиент, которому нужен код Excel VBA, который создает значения формул, перемещенные в VB.NET. Он занимается предоставлением финансовой аналитики, в данном случае - надстройкой для Excel. Я перевел VBA в код VB.NET, который работает в отдельной DLL. DLL скомпилирована как COM-сервер, потому что, ну, в общем, должны быть вызваны Excel .NET UDF. Пока все хорошо: ячейки Excel имеют «= foo (Range1, Range2, ...)», вызывается UDF VB.NET Com Server, и ячейка получает значение, соответствующее значению кода VBA.
Проблема
Код VB.NET намного медленнее. Я могу растянуть ряд формул на основе VBA и получить мгновенный расчет. Я могу растянуть сопоставимый диапазон формул на основе VB.NET, и вычисление занимает 5-10 секунд. Это заметно медленнее и неприемлемо для клиента.
Есть несколько возможностей, которые мне приходят в голову:
- Собственная компиляция VBA быстрее из-за отсутствия переключателя
- DLL может быть загружена и выгружена для каждого вызова UDF
- DLL вызывает методы Excel WorksheetFunction и требует объект Application, а создание объекта Application стоит дорого
- вызов метода Excel WorksheetFunction из DLL стоит дорого
Я не думаю, что (2) верно, потому что я помещаю вызовы для добавления к файлу в функции Shared New, Public New и Finalize, и все, что я получаю, это:
Shared Sub New
Public Sub New
Finalize
когда я открываю электронную таблицу, несколько раз растягиваю диапазон формул и закрываю электронную таблицу.
Я не думаю, что (3) верно, поскольку запись в файл показывает, что объект Application создается только один раз.
Вопрос
Как мне выяснить, что занимает время? Как профилировать в этой среде? Есть ли очевидные улучшения?
В последней категории я попытался уменьшить количество созданий объекта Application (используемого для вызовов WorkSheetFunction), сделав его Shared:
<Guid("1ECB17BB-444F-4a26-BC3B-B1D6F07D670E")> _
<ClassInterface(ClassInterfaceType.AutoDual)> _
<ComVisible(True)> _
<ProgId("Library.Class")> _
Public Class MyClass
Private Shared Appp As Application ' Very annoying
Подходы приняты
Я пытался уменьшить зависимость от математических функций Excel, переписав свою собственную. Я заменил Min, Max, Average, Stdev, Small, Percentile, Skew, Kurtosis и еще несколько. Мой код UDF вызывает в Excel гораздо меньше. Кажется, что неизбежный вызов принимает Range в качестве аргумента и преобразует его в массив .NET для внутреннего использования.