Самый быстрый способ взаимодействия между живыми (несохраненными) данными Excel и объектами C #

Я хочу знать, что самый быстрый способ чтения и записи данных в и из открытой книги Excel в объекты c #. Фоном является то, что я хочу разработать приложение ac #, которое используется в Excel и использует данные, хранящиеся в excel.

Бизнес-логика будет находиться в приложении c #, но данные будут находиться в книге Excel. Пользователь будет использовать Excel и щелкнет кнопкой (или сделает что-то подобное) в книге excel, чтобы инициировать приложение c #. Приложение c # затем считывает данные из книги Excel, обрабатывает данные, а затем записывает данные обратно в книгу Excel.
Могут быть многочисленные блоки данных, которые должны быть считаны и записаны в книгу Excel, но они обычно будут иметь относительно небольшой размер, например 10 строк и 20 столбцов. Иногда может потребоваться обработка большого списка данных порядка 50 000 строк и 40 столбцов.

Я знаю, что это относительно легко сделать, используя VSTO, но я хочу знать, что самое быстрое (но все же надежное и элегантное) решение и получить представление о скорости. Я не против, если решение рекомендует использовать сторонние продукты или использует C ++.

Очевидным решением является использование VSTO или interop, но я не знаю, что такое производительность по сравнению с VBA, которую я сейчас использую для чтения в данных, или если есть какие-либо другие решения.

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

http://www.experts-exchange.com/Microsoft/Development/VSTO/Q_23635459.html

Благодарю.

Если приложение C # является автономным приложением, то всегда будет задействован кросс-процесс, который будет перегружать любые оптимизации, которые вы можете сделать, переключая языки, например, с C # на C ++. Придерживайтесь своего наиболее предпочтительного языка в этой ситуации, который звучит как C #.

Однако, если вы хотите сделать надстройку, которая работает в Excel, ваши операции позволят избежать межпроцессных вызовов и работать примерно на 50 раз быстрее.

Если вы работаете в Excel в качестве надстройки, VBA является одним из самых быстрых вариантов, но он все еще связан с COM, поэтому вызовы C ++ с использованием надстройки XLL будут самыми быстрыми. Но VBA все еще довольно быстр в плане вызовов объектной модели Excel. Тем не менее, что касается фактической скорости вычислений, VBA работает как pcode, а не как полностью скомпилированный код, и поэтому выполняется примерно на 2-3 раза медленнее, чем собственный код. Это звучит очень плохо, но дело не в том, что подавляющее большинство времени выполнения, взятое с типичной надстройкой или приложением Excel, связано с вызовами объектной модели Excel, поэтому VBA против полностью скомпилированного надстройки COM, скажем, используя изначально составленный VB 6.0, будет только примерно на 5-15% медленнее, что не заметно.

VB 6.0 является скомпилированным COM-подходом и работает на 2-3 раза быстрее, чем VBA для вызовов, не связанных с Excel, но VB 6.0 составляет около 12 лет на данный момент и не будет работать в режиме 64 бит, скажем, при установке Office 2010, который может быть установлен для запуска 32-битного или 64-битного. Использование 64-битного Excel на данный момент крошечное, но будет расти в использовании, поэтому я бы избегал VB 6.0 по этой причине.

C #, если в процессе работы в качестве надстройки Excel будут выполняться вызовы объектной модели Excel с такой же скоростью, как VBA, и выполнять вызовы, отличные от Excel, на 2-3 раза быстрее, чем VBA – если они выполняются без ошибок. Однако подход, рекомендованный Microsoft, заключается в том, чтобы полностью выполнить подгонку, например, с помощью мастера COM Shim Wizard . Благодаря тому, что Excel защищен от вашего кода (если он неисправен), и ваш код полностью защищен от других сторонних надстроек, которые в противном случае могут вызвать проблемы. Тем не менее, нижняя сторона этого заключается в том, что исправленное решение работает в пределах отдельного AppDomain, для чего требуется кросс-админ-марширование, которое приводит к штрафу за скорость выполнения около 40x – что очень заметно во многих контекстах.

Надстройки с использованием Visual Studio Tools for Office (VSTO) автоматически загружаются в прокладку и выполняются в отдельном приложении AppDomain. Этого нельзя избежать, если использовать VSTO. Таким образом, вызовы в объектную модель Excel также будут приводить к ухудшению скорости выполнения примерно 40 раз. VSTO – великолепная система для создания очень богатых надстроек Excel, но скорость исполнения – это ее слабость для таких приложений, как ваша.

ExcelDna – бесплатный проект с открытым исходным кодом, который позволяет вам использовать код C #, который затем преобразуется для вас в надстройку XLL, которая использует код C ++. То есть ExcelDna анализирует ваш код на C # и создает для вас необходимый код C ++. Я не использовал его сам, но я знаком с процессом, и это очень впечатляет. ExcelDna получает очень хорошие отзывы от тех, кто ее использует. [Изменить: Обратите внимание на следующую коррекцию в соответствии с комментариями Govert ниже: «Привет, Майк, я хочу добавить небольшую поправку, чтобы прояснить реализацию Excel-Dna: все клещи с управляемым доступом к Excel работают во время выполнения из вашей управляемой сборки, используя reflection – там не является дополнительным этапом предварительной компиляции или генерации кода на C ++. Кроме того, несмотря на то, что Excel-Dna использует .NET, не требуется никакого взаимодействия с COM при разговоре с Excel – в качестве .xll собственный интерфейс может использоваться непосредственно из .NET. (хотя вы также можете использовать COM, если хотите). Это позволяет использовать высокопроизводительные UDF и macros ». – Говерт]

Вы также можете посмотреть надстройку Express. Это не бесплатно, но это позволит вам вводить код на C #, и, хотя он подгоняет ваше решение в отдельный AppDomain, я считаю, что его скорость исполнения невыполнима. Если я правильно понимаю скорость выполнения, то я не уверен, как это работает надстройкой Express, но он может использовать что-то, называемое FastPath AppDomain marshaling. Однако не цитируйте меня ни по одному из них, поскольку я не очень хорошо знаком с Add-in Express. Вы должны проверить это и провести собственное исследование. [Редактировать: читайте ответ Чарльза Уильямса, похоже, что Add-in Express разрешает доступ к COM и C API. И Говерт утверждает, что ДНК Excel также позволяет использовать как COM, так и быстрый доступ к C API. Поэтому вы, вероятно, захотите проверить оба варианта и сравнить их с ExcelDna.]

Мой совет – исследовать надстройку Express и ExcelDna. Оба подхода позволят вам использовать код C #, который вам кажется наиболее знакомым.

Другой основной проблемой является то, как вы делаете свои звонки. Например, Excel работает очень быстро, когда обрабатывает весь диапазон данных, передаваемых обратно и вперед в виде массива. Это намного эффективнее, чем цикл по ячейкам по отдельности. Например, следующий код использует метод доступа Excel.Range.set_Value для назначения массиву значений 10 x 10 для диапазона ячеек 10 x 10 за один снимок:

void AssignArrayToRange() { // Create the array. object[,] myArray = new object[10, 10]; // Initialize the array. for (int i = 0; i < myArray.GetLength(0); i++) { for (int j = 0; j < myArray.GetLength(1); j++) { myArray[i, j] = i + j; } } // Create a Range of the correct size: int rows = myArray.GetLength(0); int columns = myArray.GetLength(1); Excel.Range range = myWorksheet.get_Range("A1", Type.Missing); range = range.get_Resize(rows, columns); // Assign the Array to the Range in one shot: range.set_Value(Type.Missing, myArray); } 

Аналогичным образом можно использовать метод доступа Excel.Range.get_Value для считывания массива значений из диапазона за один шаг. Выполнение этого, а затем циклическое перемещение значений внутри массива происходит намного быстрее, чем циклическое изменение значений внутри ячеек диапазона.

Я возьму это как вызов и сделаю ставку на самый быстрый способ перетасовать ваши данные между Excel и C #, чтобы использовать Excel-Dna – http://exceldna.codeplex.com . (Отказ от ответственности: я разрабатываю Excel-Dna, но это все еще так)

Поскольку он использует собственный .xll-интерфейс, он пропускает все накладные расходы на интеграцию COM, которые вы имели бы с VSTO или другим подходом COM-надстройки. С помощью Excel-Dna вы можете создать макрос, который подключается к кнопке меню или ленты, которая считывает диапазон, обрабатывает его и записывает обратно в диапазон в Excel. Все с использованием собственного интерфейса Excel из C # – не COM-объект в поле зрения.

Я сделал небольшую тестовую функцию, которая принимает текущий выбор в массив, квадратизирует каждое число в массиве и записывает результат в Лист 2, начиная с ячейки A1. Вам просто нужно добавить (бесплатную) рабочую среду Excel-Dna, которую вы можете скачать с http://exceldna.codeplex.com .

Я читал в C #, обрабатывал и записывал обратно в Excel миллионный диапазон в течение секунды. Это достаточно быстро для вас?

Моя функция выглядит так:

 using ExcelDna.Integration; public static class RangeTools { [ExcelCommand(MenuName="Range Tools", MenuText="Square Selection")] public static void SquareRange() { object[,] result; // Get a reference to the current selection ExcelReference selection = (ExcelReference)XlCall.Excel(XlCall.xlfSelection); // Get the value of the selection object selectionContent = selection.GetValue(); if (selectionContent is object[,]) { object[,] values = (object[,])selectionContent; int rows = values.GetLength(0); int cols = values.GetLength(1); result = new object[rows,cols]; // Process the values for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (values[i,j] is double) { double val = (double)values[i,j]; result[i,j] = val * val; } else { result[i,j] = values[i,j]; } } } } else if (selectionContent is double) { double value = (double)selectionContent; result = new object[,] {{value * value}}; } else { result = new object[,] {{"Selection was not a range or a number, but " + selectionContent.ToString()}}; } // Now create the target reference that will refer to Sheet 2, getting a reference that contains the SheetId first ExcelReference sheet2 = (ExcelReference)XlCall.Excel(XlCall.xlSheetId, "Sheet2"); // Throws exception if no Sheet2 exists // ... then creating the reference with the right size as new ExcelReference(RowFirst, RowLast, ColFirst, ColLast, SheetId) int resultRows = result.GetLength(0); int resultCols = result.GetLength(1); ExcelReference target = new ExcelReference(0, resultRows-1, 0, resultCols-1, sheet2.SheetId); // Finally setting the result into the target range. target.SetValue(result); } } 

В дополнение к комментариям Майка Розенблюма об использовании массивов, я хотел бы добавить, что я использовал самый подход (массивы VSTO +), и когда я измерил его, фактическая скорость чтения была в миллисекундах. Просто не забудьте отключить обработку событий и обновление экрана до чтения / записи и не забудьте снова включить после завершения операции.

Используя C #, вы можете создавать массивы на 1 основе точно так же, как и сам Excel VBA. Это очень полезно, особенно потому, что даже в VSTO, когда вы извлекаете массив из объекта Excel.Range, массив основан на 1, поэтому сохранение ориентированных на Excel массивов на основе 1 помогает избежать необходимости всегда проверять, массив основан на базе одного или на основе нуля. (Если позиция столбца в массиве имеет значение для вас, необходимость иметь дело с массивами на основе 0 и 1 может стать настоящей болью).

Обычно чтение Excel.Range в массив будет выглядеть примерно так:

 var myArray = (object[,])range.Value2; 

Мое изменение массива-записи Майка Розенблюма использует массив на основе 1:

 int[] lowerBounds = new int[]{ 1, 1 }; int[] lengths = new int[] { rowCount, columnCount }; var myArray = (object[,])Array.CreateInstance(typeof(object), lengths, lowerBounds); var dataRange = GetRangeFromMySources(); // this example is a bit too atomic; you probably want to disable // screen updates and events a bit higher up in the call stack... dataRange.Application.ScreenUpdating = false; dataRange.Application.EnableEvents = false; dataRange = dataRange.get_Resize(rowCount, columnCount); dataRange.set_Value(Excel.XlRangeValueDataType.xlRangeValueDefault, myArray); dataRange.Application.ScreenUpdating = true; dataRange.Application.EnableEvents = true; 

Самый быстрый интерфейс для данных Excel – это API C. Существует ряд продуктов, которые связывают .NET с Excel, используя этот интерфейс.

2 продукта Мне нравится, что это Excel DNA (который является бесплатным и открытым исходным кодом) и Addin Express (который является коммерческим продуктом и имеет как API C, так и COM-интерфейс).

Во-первых, ваше решение не может быть Excel UDF (пользовательская функция). В наших руководствах мы приводим следующее определение: «Excel UDF используются для создания пользовательских функций в Excel для конечного пользователя, чтобы использовать их в формулах». Я бы не прочь, если вы предложите лучшее определение 🙂

Это определение показывает, что UDF не может добавить кнопку в пользовательский интерфейс (я знаю, что XLL могут изменять интерфейс CommandBar) или перехватывать сочетания клавиш, а также события Excel.

То есть, ExcelDNA выходит за пределы области действия, потому что она предназначена для разработки надстроек XLL. То же самое относится к функциональности надстройки Excel, ориентированной на Excel, поскольку она позволяет разрабатывать надстройки XLL и надстройки Excel Automation.

Поскольку вам нужно обрабатывать события Excel, ваше решение может быть автономным приложением, но есть очевидные ограничения такого подхода. Единственный реальный способ – создать надстройку COM; он позволяет обрабатывать события Excel и добавлять пользовательские элементы в интерфейс Excel. У вас есть три возможности:

  • VSTO
  • Надстройка Express (функция надстройки COM)
  • Общая надстройка (см. Соответствующий элемент в диалоговом окне «Новый проект» в VS)

Если говорить о разработке надстройки Excel COM, то эти 3 средства предоставляют различные функции: визуальные дизайнеры, shimming и т. Д. Но я не думаю, что они отличаются скоростью доступа к объектной модели Excel. Скажем, я не знаю (и не могу себе представить), почему получение COM-объекта из AppDomain по умолчанию должно отличаться от получения того же COM-объекта из другого AppDomain. BTW, вы можете проверить, влияет ли регулировка скорости на скорость работы, создав общую надстройку, а затем с помощью мастера COM Shim Wizard, чтобы подделать ее.

Скорость II. Как я писал вам вчера: «Лучший способ ускорить чтение и запись в ряд ячеек – создать переменную типа Excel.Range, относящуюся к этому диапазону, а затем прочитать / записать массив из / в свойство Value от переменной “. Но, вопреки тому, что говорит Франческо, я не отношу это к VSTO; это особенность объектной модели Excel.

Скорость III. Самые быстрые Excel UDF написаны на родном C ++, а не на любом языке .NET. Я не сравнивал скорость надстройки XLL, созданной ExcelDNA и Add-in Express; Я не думаю, что вы найдете здесь существенную разницу.

Подводить итоги. Я убежден, что вы ошибаетесь: надстройки COM, основанные на надстройке Express, VSTO или общей надстройке, должны читать и записывать ячейки Excel с одинаковой скоростью. Я буду рад (искренне), если кто-то опровергнет это заявление.

Теперь по твоим другим вопросам. VSTO не позволяет разрабатывать надстройку COM, поддерживающую Office 2000-2010. Это требует трех разных кодовых баз и по крайней мере двух версий Visual Studio для полной поддержки Office 2003-2010; вам нужно иметь сильные нервы и часть удачи для развертывания надстройки на основе VSTO для Excel 2003. С помощью Add-in Express вы создаете надстройку COM для всех версий Office с единой кодовой базой; Add-in Express предоставляет вам проект настройки, который готов для установки надстройки в Excel 2000-2010 (32-разрядная и 64-разрядная); Кроме того, развертывание ClickOnce также находится на борту.

VSTO превосходит надстройку Express в одной области: позволяет создавать так называемые надстройки уровня документа. Представьте себе книгу или шаблон с некоторым кодом .NET за ним; Однако я не удивлюсь, если развертывание таких вещей будет кошмаром.

О событиях Excel. Все события Excel перечислены в MSDN, например, см. События Excel 2007

Отношения с Беларусью (GMT + 2),

Руководитель группы надстроек экс-президента Андрей Смолин

Я использовал код VBA (макрос) для сбора и уплотнения данных и получения этих данных одним вызовом на C # и наоборот. Вероятно, это будет наиболее эффективный подход.

Используя C #, вам всегда нужно будет использовать некоторую сортировку. Используя VSTO или COM Interop, уровень подстилающей связи (сортировка служебных данных) одинаков.

В VBA (Visual Basic для приложения) вы работаете непосредственно с объектами в Excel. Таким образом, доступ к этим данным всегда будет быстрее.

Но … Как только у вас есть данные на C #, манипулирование этими данными может быть намного быстрее.

Если вы используете VB6 или C ++, вы также проходите через интерфейс COM, и вы также столкнетесь с перекрестным процессом сортировки.

Таким образом, вы ищете способ минимизации перекрестных вызовов процессов и сортировки.

Interesting Posts

Как изменить кодировку символов в текстовом файле в OpenOffice.org writer?

Чтение больших текстовых файлов с streamами в C #

Получение всех изменений, внесенных в объект в Entity Framework

Программное обеспечение, отображающее время NTP-сервера

Синхронизировать Outlook 2007 с Календарем Google, используя настройку уведомлений по умолчанию в GCal для новых событий?

Как получить имя устройства из сканирования, например nmap в Linux

Можно ли определить широковещательный приемник как внутренний class в файле манифеста?

Уменьшение высоты бутстрапа 3.0 navbar

Arrow Box с CSS

Android LinearLayout с цветовым ресурсом: что я делаю неправильно?

Как заставить клавиши Ctrl + Left / Right работать прямо в tmux?

Alt Tab (Task Switcher), случайное изменение заданной конфигурации строк / столбцов

Лучший с открытым исходным кодом Mixed Integer Optimization Solver

Сложный объект и привязка модели ASP.NET MVC

Анализ Квай-квадратов с использованием для цикла в R

Давайте будем гением компьютера.