Если вы используете NERDTree в качестве своего проводника / тире файла, я бы рекомендовал xolox / vim-session plugin вместо встроенной команды mksession. По какой-то причине: mksession не восстанавливает буферы NERDTree. Ваш пробег может отличаться, но я думал поделиться своим опытом.
Если приложение 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 для чтения массива значений из диапазона за один шаг. Делать это, а затем циклически перебирать значения внутри массива значительно быстрее, чем перебирать значения внутри ячеек диапазона по отдельности.
Я приму это как вызов и сделаю ставку, что самый быстрый способ переместить ваши данные между 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);
}
}
В дополнение к комментариям Майка Розенблюма об использовании массивов, я хотел бы добавить, что я использую сам подход (массивы 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 (коммерческий продукт, в котором есть как C API, так и COM-интерфейс).
Я использовал VBA-код (макрос) для сбора & amp; сжать данные и получить эти данные за один вызов C #, и наоборот. Вероятно, это будет наиболее эффективный подход.
Используя C #, вам всегда нужно использовать маршаллинг. При использовании VSTO или COM Interop нижележащий коммуникационный уровень (распределение служебных данных) одинаков.
В VBA (Visual Basic для приложений) вы работаете непосредственно с объектами в Excel. Таким образом, доступ к этим данным всегда будет быстрее.
Но .... Если у вас есть данные в C #, манипулирование этими данными может быть намного быстрее.
Если вы используете VB6 или C ++, вы также проходите через интерфейс COM и столкнетесь с межпроцессным маршалингом.
Итак, вы ищете метод для минимизации межпроцессных вызовов и маршаллинга.
Во-первых, ваше решение не может быть Excel UDF (пользовательская функция). В наших руководствах мы даем следующее определение: «UDF Excel используются для создания пользовательских функций в Excel, чтобы конечный пользователь мог использовать их в формулах». Я не возражаю, если вы предложите более точное определение :)
Это определение показывает, что UDF не может добавить кнопку в пользовательский интерфейс (я знаю, что XLL могут изменять пользовательский интерфейс CommandBar) или перехватывать сочетания клавиш, а также События Excel.
То есть ExcelDNA выходит за рамки, поскольку он предназначен для разработки надстроек XLL. То же самое относится к функциональности надстройки Express, нацеленной на Excel, поскольку она позволяет разрабатывать надстройки XLL и надстройки Excel Automation.
Поскольку вам нужно обрабатывать события Excel, ваше решение может быть автономным приложением, но существуют очевидные ограничения такого подхода. Единственный реальный способ - создать надстройку COM; это позволяет обрабатывать события Excel и добавлять пользовательские элементы в пользовательский интерфейс Excel. У вас есть три возможности:
Если говорить о разработке надстройки 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