Деградация скорости у функции setDataArray()

Автор zmeishe, 3 декабря 2019, 11:54

0 Пользователи и 1 гость просматривают эту тему.

zmeishe

Необходимо из приложения средствами api LibreOffice передать в Calc значения 900 тыс строк и 20 столбцов.
Если всё это выгрузить в файл CSV, а затем открыть Calc`ом, то он потратит около 5 минут времени.

Если использовать функцию setDataArray, то сначала скорость высокая - порядка 100 тыс записей в минуту, затем скорость деградирует(сильно снижается). В итоге все данные можно передать только за 30-40 минут, вместо 8-10 мин.

Как ускорить работу функции setDataArray, чтобы скорость не снижалась?

Подробности:
LibreOffice 5.2.7.7
Debian 9
Весь массив вывожу частями по 50 тыс строк (так чтобы не более 1 млн ячеек за шаг)
После каждой порции сбрасываю флаг
         Reference < XModifiable > xModifiable( xCalcComponent, UNO_QUERY );
         xModifiable->setModified( sal_False );

Экспериментировал с разным количеством строк за один шаг: от 1 тыс до 100 тыс. Результат одинаковый. Сначала быстро, затем медленно.
Единственное, что прибавило скорости, это передача даты и времени не строками, а числовым преставлением.

Как будто Calc накапливает, что-то, что мешает ему. Как это "что-то" отключить, сбросить или очистить, чтобы он не тратил время и скорость приблизилась к скорости открытия файла CSV ?

bigor

Цитата: zmeishe от  3 декабря 2019, 11:54900 тыс строк и 20 столбцов.
Если всё это выгрузить в файл CSV, а затем открыть Calc`ом, то он потратит около 5 минут

Цитата: zmeishe от  3 декабря 2019, 11:54setDataArray, то сначала скорость высокая - порядка 100 тыс записей в минуту
Т.е. на 900 тыс уйдет 9 минут, в чем выйгрыш по сравнению с csv?
Поддержать разработчиков LibreOffice можно можно тут, а наш форум вот тут

zmeishe

Цитата: Bigor от  3 декабря 2019, 12:25в чем выйгрыш по сравнению с csv?

Выигрыш в том, что пользователю не надо мышетыканием заниматься. И копипастить тоже ничего не надо.
Таблицы выходят с многоуровневыми заголовками. С замороженными заголовками. Лист подогнан по ширине страницы. Страница повёрнута Ландшафт/Портрет в зависимости от количества столбцов. Числа форматированы с нужным количеством знаков после запятой и с разделением разрядов. Нулевые значения отключены(ячейка с нулями выглядит пустой).
Некоторые отчёты на разных листах одной книги Calc.
Отчёты 300 тыс строк и до 6-ти столбцов со всей этой красотой  setDataArray выгружает за 40 сек.

Количество столбцов около 10 существенно снижает скорость.

В этом конкретном отчёте столбцов 20 и вся красота пока отключена.
У заказчиков есть возможность воспользоваться CSV, но они хотят то, к чему привыкли. И никто не хочет ждать.


mikekaganski

Насколько я понимаю, Bigor предлагает программно импортировать CSV и отформатировать результат для достижения того же?
С уважением,
Михаил Каганский

zmeishe

Оно, конечно, можно.
Но хотелось бы понять - у открытия файла и setDataArray разные алгоритмы? И зачем это разработчикам Open/Libre Office ?
Я ещё могу понять разный подход для xCell->setValue(...) и xCellRange->setDataArray(...).
Но для setDataArray() и открытием файла, думаю механизм один.
Просто мы не знаем, что он там ещё делает и что там можно программно отключить.

mikekaganski

Так соберите отладочную сборку ЛО и посмотрите :) На самом деле никак иначе не ответить на Ваш вопрос.
С уважением,
Михаил Каганский

zmeishe

Ещё заметил.
Например, отчёт содержит 1.7млн строк и 6 столбцов.
Вывожу на разные листы одной книги Calc приблизительно по 280 тыс строк. Где-то больше, где-то меньше. Всего 9 листов.
На всё, вместе с красотой, уходит 12-15 мин.

Таким образом, деградация скорости происходит при выводе 900 тыс строк на один лист. Первые 200-300 тыс выгружает быстро, а дальше на что-то теряет время. То есть по мере удаления вставляемых диапазонов ячеек от начала листа, скорость падает.

zmeishe

Цитата: mikekaganski от  3 декабря 2019, 13:20Так соберите отладочную сборку ЛО

Это крайний случай. Пока надеюсь на помощь. Может кто-то уже догадался куда копать.

kompilainenn

Поддержать разработчиков LibreOffice можно тут, а наш форум вот тут

zmeishe

#9
Я его поборол.

Вывел 900 тыс строк в 20 столбцов меньше чем за минуту. Причём, вывел со всеми прибамбасами форматирования.
И заметьте, это много быстрее чем через файл CSV.

Стал выводить не блоками в несколько тысяч строк и в 20 столбцов, а блоками в 900 тыс строк и в один столбец.
Заметил следующее.
Он уходит в "даун" на пустых ячейках. Столбцы, где каждая ячейка имеет значение он выводит за 1-2 сек на 900 тыс строк.
Пустым ячейкам с числами, датами и временем  я присвоил значение 0.
Пустым ячейкам со строками я присвоил значение "-".
А до этого я присваивал пустые кавычки "". Вот тут-то он и начинал "дурить" более часа.

Сейчас такое неудобство. Нулевые даты выглядят 30.12.1899. Нулевое время 00:00:00.

Подскажите, что следует присвоить элементу массива для функции setDataArray, чтобы ячейка была пустой для дат, времени, строк?

У элемента массива есть функция clear(), но тогда для этой ячейки Calc выведет что-то вроде #N/A или #Н/Д. Это некрасиво. Что ему присвоить, чтобы было пусто?


mikekaganski

Не могу воспроизвести.

sub DataArray
  doc = ThisComponent
  range = doc.Sheets(0).getCellRangeByPosition(0,0,0,900000-1)
  dim data(0 to 900000-1)
  for i = 0 to 900000 - 1
    data(i) = array("")
  next i
  t = now()
  range.setDataArray(data())
  MsgBox Format(now() - t, "ss "" s""")
end sub


даёт на чистом листе 3 с (естественно, я не учитываю начальный этап по заполнению массива - в Basic это значительное время, но тоже в пределах 3-4 с).

Замена "" на empty не меняет картину.
С уважением,
Михаил Каганский

zmeishe

У меня SDK C++. Пустые кавычки или пробел в кавычках сносят Calc`y башню.
У меня там массив массивов или массив перечислений.
Выглядит это так
Sequence<Sequence< Any >> aRowsArray( rowCount );
Sequence< Any  > aRowValues( columnCount );

Для эксперимента с выводом блоками по одному столбцу
Sequence<Sequence< Any >> aRowsArray( rowCount );
Sequence< Any  > aRowValues( 1 );

У этого типа данных Any есть функция clear(), но она не подходит из-за вывода в ячейки значений #N/A или #Н/Д - не комильфо.
Вот что ему присвоить, чтобы было и быстро и пусто?





bigor

#12
Цитата: mikekaganski от  3 декабря 2019, 20:54Не могу воспроизвести.
Вот так воспроизводится

sub DataArray
 doc = ThisComponent
 range = doc.Sheets(0).getCellRangeByPosition(0,0,0,500000-1)
 dim data(0 to 500000-1)
 for i = 0 to 500000 - 1
    If i mod 10 = 0 Then
    data(i) = array("")
    Else
    data(i) = array(i)
    End if
 next i
 Print "Go"
 t = now()
 range.setDataArray(data())
 MsgBox Format(now() - t, "ss "" s""")
end sub


в данном виде 28 с
если data(i) = array("") заменить на data(i) = array(i)
то около 3 с

зы формат первого столбца дата
Поддержать разработчиков LibreOffice можно можно тут, а наш форум вот тут

mikekaganski

С уважением,
Михаил Каганский

mikekaganski

Замедление вижу, надо поковыряться.

Тем временем воспользуйтесь числовым форматом, который просто скрывает нули:

sub DataArray
  doc = ThisComponent

  range = doc.Sheets(0).getCellRangeByPosition(0,0,0,900000-1)
  cell = range.GetCellByPosition(0, 0)
  locale = doc.NumberFormats.getByKey(cell.NumberFormat).Locale
  nFmtId = doc.NumberFormats.queryKey("0;-0;", locale, False)
  if nFmtId = -1 then _
    nFmtId = ThisComponent.NumberFormats.addNew("0;-0;", locale)
  range.NumberFormat = nFmtId

  dim data(0 to 900000-1)
  for i = 0 to 900000 - 1
    if (i mod 10 = 0) Then data(i) = array(0) else data(i) = array(i)
  next i
  t = now()
  range.setDataArray(data())
  MsgBox Format(now() - t, "[ss] "" s""")
end sub
С уважением,
Михаил Каганский