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

Если вы используете NERDTree в качестве своего проводника / тире файла, я бы рекомендовал xolox / vim-session plugin вместо встроенной команды mksession. По какой-то причине: mksession не восстанавливает буферы NERDTree. Ваш пробег может отличаться, но я думал поделиться своим опытом.

29
задан jw_pr 1 October 2010 в 14:47
поделиться

6 ответов

Если приложение 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 . Благодаря использованию Shimmed Excel защищен от вашего кода (если он неисправен), а ваш код полностью защищен от других сторонних надстроек, которые в противном случае могли бы вызвать проблемы. Обратной стороной этого является, однако, то, что решение с ограниченным доступом работает в отдельном домене приложений, что требует маршалинга между доменами приложений, что влечет за собой снижение скорости выполнения примерно в 40 раз, что очень заметно во многих контекстах.

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

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

Вы также можете посмотреть на надстройку Express. Это не бесплатно, но это позволит вам кодировать на C #, и, хотя оно объединяет ваше решение в отдельный домен приложений, я считаю, что скорость его выполнения является выдающейся. Если я правильно понимаю скорость его выполнения, то я не уверен, как это делает Add-in Express, но он может воспользоваться преимуществами маршалинга FastPath AppDomain. Однако не цитируйте меня по этому поводу, поскольку я не очень знаком с надстройкой Express. Вы должны проверить это и сделать свое собственное исследование. [Редактировать: читая ответ Чарльза Уильямса, похоже, что Add-in Express обеспечивает доступ к COM и C API. А Говерт заявляет, что Excel DNA также обеспечивает как 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 для чтения массива значений из диапазона за один шаг. Делать это, а затем циклически перебирать значения внутри массива значительно быстрее, чем перебирать значения внутри ячеек диапазона по отдельности.

38
ответ дан Mike Rosenblum 1 October 2010 в 14:47
поделиться

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

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

Я сделал небольшую тестовую функцию, которая переносит текущий выбор в массив, возводит в квадрат каждое число в массиве и записывает результат в лист 2, начиная с ячейки A1. Вам просто нужно добавить (бесплатную) среду выполнения Excel-ДНК, которую вы можете загрузить с 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);
}
}
40
ответ дан Govert 1 October 2010 в 14:47
поделиться

В дополнение к комментариям Майка Розенблюма об использовании массивов, я хотел бы добавить, что я использую сам подход (массивы 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;
4
ответ дан code4life 1 October 2010 в 14:47
поделиться

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

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

3
ответ дан Charles Williams 1 October 2010 в 14:47
поделиться

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

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

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

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

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

Итак, вы ищете метод для минимизации межпроцессных вызовов и маршаллинга.

0
ответ дан GvS 1 October 2010 в 14:47
поделиться

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

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

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

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

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

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

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

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

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

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

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

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

С уважением, из Беларуси (GMT + 2),

Андрей Смолин Руководитель надстройки Express Team

3
ответ дан Andrei Smolin - Add-in Express 1 October 2010 в 14:47
поделиться
Другие вопросы по тегам:

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