Главная
» PC Советы
»
Ускорьте работу макросов Calc, считывая и записывая данные пакетами.
Ускорьте работу макросов Calc, считывая и записывая данные пакетами.
Наиболее надежным первым способом ускорения медленной работы макроса Calc является замена многократных операций чтения и записи ячеек одной операцией чтения диапазона, циклом в памяти и одной операцией записи диапазона. Это сокращает количество вызовов между Basic и Calc; однако это не гарантирует фиксированного прироста скорости, поскольку формулы, форматирование, размер файла и логика макроса также могут доминировать во время выполнения. Пример ниже изменяет столбец состояния и показывает, как измерить как скорость, так и корректность. Информация об API была проверена по документации LibreOffice 26.8 9 октября 2026 года.
Что следует улучшить, и как вы будете это измерять?
Запустите текущий макрос на копии рабочей книги и запишите затраченное время. Используйте новую копию с теми же исходными данными для старого и измененного макросов или восстановите входные данные между запусками; в противном случае второй запуск может выполнить меньше работы. Сохраняйте количество строк, параметры вычислений и условия вывода неизменными. Повторяйте каждый запуск и сравнивайте типичное время, а не полагайтесь на один необычно быстрый запуск. Убедитесь, что результат соответствует ожидаемому правилу. Макрос, который завершается быстрее, но изменяет не те строки, не является улучшением.
Функция LibreOffice Basic Timerсообщает количество секунд с полуночи; присвойте её Longпеременным, чтобы получить числовое значение в секундах. Для короткого запуска запишите начальное и конечное значения и вычтите их. Если конечное значение меньше, значит, запуск пересёк полночь, поэтому добавьте к разнице 86 400 секунд. Таймер сообщает целые секунды; используйте ScriptForgeслужбу таймера для точности до миллисекунд. См. документацию по таймеру LibreOffice Basic и документацию по службе таймера ScriptForge . Открытие, сохранение и ручная проверка рабочей книги должны происходить вне измеренного интервала, если только это не является частью реальной задачи.
Начинайте с одного и того же непрерывного диапазона данных и условий рабочей книги для каждого запуска измерения времени.
Почему большие макросы Calc замедляют работу?
Цикл, который getCellByPosition()многократно вызывает функции или считывает и записывает свойства отдельных ячеек, заставляет Calc выполнять каждую операцию через интерфейс Basic-to-Calc. При большом количестве строк и столбцов эти вызовы могут суммироваться, даже если само преобразование простое. Цикл по массиву в памяти по-прежнему обращается к каждой строке, но позволяет избежать отдельного вызова API ячейки для каждого значения.
Сначала удалите операции, не влияющие на результат: избегайте выбора или активации ячеек внутри цикла, не пересчитывайте и не форматируйте ячейки многократно, если достаточно одной операции с диапазоном, и не обрабатывайте целые столбцы, если требуется только ограниченный блок данных. Эти изменения помогут выявить истинное узкое место, прежде чем добавлять дополнительные элементы управления.
Как обработать диапазон значений в виде массива?
Используйте прямоугольный диапазон, содержащий только те значения, которые ваш макрос намерен изменить. В примере предполагается наличие листа с именем Data, строки заголовка в строке 1 и значений статуса в столбце C. Измените имя листа и диапазон в соответствии с вашей рабочей книгой. API getDataArray()возвращает диапазон в виде строк, содержащих значения; setDataArray()записывает обратно в этот диапазон массив того же размера.
Перед началом цикла обработки данных в памяти необходимо один раз считать данные из требуемого прямоугольного диапазона.
Sub UpdateStatuses
Dim oSheet As Object
Dim oRange As Object
Dim aData As Variant
Dim i As Long
oSheet = ThisComponent.Sheets.getByName("Data")
oRange = oSheet.getCellRangeByName("A2:C10001")
aData = oRange.getDataArray()
For i = LBound(aData) To UBound(aData)
If aData(i)(2) = "pending" Then
aData(i)(2) = "review"
End If
Next i
oRange.setDataArray(aData)
End Sub
Массив строк имеет нулевую индексацию: aData(i)(2)он обращается к третьему столбцу в каждой строке. В данном случае это столбец C, поскольку выбранный диапазон начинается с A. Внешняя последовательность массива представляет строки, а каждая внутренняя последовательность — столбцы. Диапазон, передаваемый в функцию, setDataArray()должен иметь те же размеры, что и массив; несоответствие вызовет ошибку. См. справочник по API LibreOffice XCellRangeData и документацию по массивам LibreOffice ScriptForge .
Примените правило в памяти, затем запишите полученный массив в Calc одним вызовом.
Не включайте ячейки с формулами в обновления, содержащие только значения.
getDataArray()Возвращает значения ячеек в виде чисел или строк, а не исходного текста формулы. Если вы считываете диапазон, содержащий формулы, и записываете этот массив обратно с помощью метода `return` , эти формулы могут быть заменены их текущими результатами. Ограничьте метод `return` массивом значений ячейками ввода/вывода, которые должны содержать значения. Когда макрос должен сохранять или изменять формулы, используйте методы `return` и setDataArray()`return` массива формул или работайте только с диапазоном, не содержащим формулы. В справочнике API XCellRangeFormula описан этот отдельный интерфейс.getFormulaArray()setFormulaArray()
Когда следует изменять параметры вычислений или отображения?
Проверяйте эти параметры только после измерения версии массива. Если пересчет формул занимает большую часть выполнения, вы можете запросить информацию isAutomaticCalculationEnabled(), временно отключить автоматический расчет с помощью команды enableAutomaticCalculation(False), затем восстановить исходные настройки и пересчитать измененные ячейки при необходимости. Поместите восстановление в путь очистки, чтобы ошибка не оставила рабочую книгу в режиме ручного расчета. Не отключайте расчет, если макросу требуются свежие результаты формул между шагами. В документации LibreOffice calculate()указано, что пересчет измененных ячеек calculateAll()приводит к принудительному полному пересчету и сам по себе может быть ресурсоемким. См. справочник по API XCalculatable .
lockControllers()Можно приостановить некоторые уведомления, используемые для обновления отображения, пока макрос изменяет множество ячеек. Каждая блокировка должна быть связана с unlockControllers(), в том числе и при завершении макроса через обработчик ошибок. Это уменьшает объем работы по обновлению отображения; при этом не отключается вычисление формул и не превращается логика для каждой ячейки в пакетную операцию. Используйте это для решения проблемы узкого места, связанного с обновлением экрана, а не в качестве замены массивов диапазонов. См. справочник по API XModel .
Как проверить изменения и понять, когда следует сменить метод?
Запустите исправленный макрос на копии рабочей книги и запишите время его выполнения в тех же условиях, что и для базового варианта. Сравните затронутые строки, незатронутые строки, формулы и итоговые значения. Сохраните, закройте и снова откройте копию, если рабочий процесс включает сохранение; это может выявить проблемы, которые можно пропустить при быстрой визуальной проверке. Стабильное улучшение должно наблюдаться при повторных запусках, при этом проверки выходных данных должны по-прежнему проходить успешно.
Подтвердите преобразованные значения и запишите измеренные временные параметры, не предполагая заранее ускорения.
Если макрос по-прежнему большую часть времени тратит на сложные формулы, форматирование, ввод-вывод файлов или сортировку, профилируйте этот этап отдельно; массивы диапазонов только уменьшают количество повторных обращений к ячейкам. Для очень больших таблиц полный массив в оперативной памяти также может потреблять значительное количество памяти. Обрабатывайте по несколько столбцов за раз или разделяйте строки на блоки, если нагрузка на память возрастает, проверяя при этом, что каждый блок начинается и заканчивается на нужной строке. Если данные уже находятся в базе данных, а задача состоит в фильтрации, группировке или обновлении записей, перенос этой работы в запрос к базе данных может быть более подходящим вариантом, чем загрузка каждой записи в Calc.