Страницы: 1
RSS
Сравнение времени работы VBA-макросов с различными алгоритмами
 
Тема, с которой все началось (изменено Sanja)

Вопрос был:
Цитата
Sanja: Как (и можно ли в принципе), напрямую, без передачи Массива в переменную, изменить какое нибудь его значение?
ответ, по-прежнему — нет. Это ограничение [на данный момент] никак обойти не удалось.

    Да, testuser, представил альтернативный вариант. За это (и вообще за подобные изыскания) ему большое спасибо. Но это никак не влияет на ограничение из вопроса. И что там по скорости? У меня есть большие сомнения, что такой "прямой доступ" будет быстрее классического подхода со словарями.

Ещё пример:
    Карты ("суперсловари" std::unordered_map) от bedvit (о чём он пишет в #11.
    Получение значения там обязательно даже просто для его просмотра/чтения.

О задаче:
    Использование массивов разной величины в качестве значений словаря — в большинстве случаев является плохой идеей. Постоянный ReDim Preserve не меньше сказывается на замедлении, чем, непосредственно, присвоение массива переменной. Если тип переменной-массива соответствует типу массива в словаре, то, конечно, будет быстрее. Не нужно работать на варианте, если можно задать специальный тип.

    Я подобный вопрос разбирал на задаче "СцепитьЕсли" — там, как раз нужно копить строки по каждому ключу.

Оптимальные варианты для подобных задач:
    1. В качестве значения накапливать строку.
s = s & sep & i (Или dic(sKey) = dic(sKey) & sep & i ). Где i — Это очередной индекс вспомогательного одномерного строкового массива.
    То есть, чтобы не тратить время на сцепку строк (они могут быть очень длинными), мы сцепляем индексы массива (указатели на эти строки в массиве, если угодно). Да — потом придётся прогнать ещё один цикл по каждой строке с индексами, чтобы их заменить на сами значения, то тесты показывали, что это заметно быстрее.
    2. Вообще не хранить строки в качестве значений словаря.
Храним в словаре указатели (индексы массива) на строки в отдельном строковом массиве. Так и извлекать ничего не нужно будет. В этом массиве строки формируем по принципу из п.1 — с помощью ещё одного вспомогательного массива.
    3. Отсортировать массив. Самый простой и быстрый вариант.
Отсортировать массив по ключам. В этом случае, у нас будет тольлко один буферный строковый массив — для каждого ключа по почереди. Кладём строки в этом массив и, после окончания очередного ключа, делаем редим и сцепляем.
    Это сработает, если у вас есть сортер от bedvit'а. В противном случае, время сортировки вполне может быть больше времени вариантов 1 и 2. Более того, если вам потом нужно эти агрегированные строки всё-равно добавить в словарь (например, чтобы проставить их по ключам на листе), то добавление пар произойдёт заметно быстрее. Проверено.
    Join строкового массива очень быстрый. Но было бы ещё быстрее, если бы была возможность задать индексы строк массива для сцепки — это бы позволило избежать ReDim Preserve и позволило бы вообще собрать все значения в один массив, в другом двумерном (Long) массиве (в том же цикле) запомнить индекс первого и последнего элемента по ключу и потом просто отдать в библу, чтобы "сделала красиво" (ил прогнать в цикле на стороне VBA).

Для подробного разбора вопроса агрегации строк по ключу я, когда-нибудь сделаю отдельную тему.
UPD: так вот же она  :D . Но там ещё много работы нужно проделать …
Изменено: Sanja - 02.06.2024 09:50:19 (Изменение названия Темы. Удаление эмоциональных сообщений)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
И что там по скорости? У меня есть большие сомнения, что такой "прямой доступ" будет быстрее классического подхода со словарями.
Ну не архи-быстрым точно, учитывая vba-шную реализацию классов и т.д.) Взять например это выражение, во время такого вызова, происходит сначала запрос элемента у коллекции по индексу и возврат ею переменной (экземп. класса) внутри Варианта. Дальше идет вызов метода экземпляра класса, обернутово в Вариант, этот метод создает вариантную ссылку помещенного внутри класса массива, обернутого таже в Вариант. Дальше метод возвращает вариантную ссылку (фактически копирует) во внешнюю вариантную временную переменную, дальше идет обращение к массиву (точнее к его ссылке), внутри Варианта и получение его элемента..
Цитата
testuser написал:
Debug.Print coll(1).Ar()(2) 'получаем значение массива способ 1
Но я вообще не задумывался о скорости, сделал этот класс просто по приколу, потому, что вопрос периодичеки такой появляется. Ну и немного интересно будет может ли иметь такой подход хотя бы какой-то смысл и если кто-то, что-то протестирует. Плюс ко всему, Variant это такая интересная универсальная вещица, как бы игрушка, и можно с помощью него делать всякие "поделки". На Хабре видел статью про использование Варианта в C++, о том что он дает определенные удобства в разработке и даже скорость..
Изменено: testuser - 31.05.2024 17:55:29
 
если по вопросу скорости ничего неизвестно, то зачем ставить её под сомнение )
 
Цитата
testuser: Но я вообще не задумывался о скорости, сделал этот класс просто по приколу, потому, что вопрос периодически такой появляется.
я-то это всё прекрасно понимаю  ;)
    Альтернативные варианты — это хорошо, но для работы нужна скорость (ещё раз — это не в претензию). Думаю, сам факт наличия "дополнительной" строки arr = dic(sKey) (критически необходимой для изменения размерности и добавления элемента) мало кого угнетает  :)

    Значит, дело в 2ух моментах (во всяком случае, для меня):
         • просто технически интересно, как без этого обойтись (и ты на это ответил). Это не проще и не быстрее, но это ответ.
         • как ускорить этот процесс (ведь понятно, что такие манипуляции тратят время "попусту"). И тут уже Я постарался ответить.

Цитата
nilske: если по вопросу скорости ничего неизвестно, то зачем ставить её под сомнение )
вот опять до меня докапываетесь  :D
    Ну глупый же вопрос (без обид) — сомнение ведь и есть история про неизвестность. Найду ли я полтинник сегодня по пути на работу? Не знаю (неизвестно), сомневаюсь. Если неизвестность/неопределённость — это 50%/50%, то сомнение это 30/70, 70/30, 20/40 — и так далее. Это склонение к одной из границ.
    Почему я сомневаюсь? Потому что коллекции сильно проигрывают словарям, а решение построено на них.
    Впрочем, без тестов нельзя утверждать (всякое бывает) — а я этого и не делал  :)
    Если вы видите McLaren и телегу, то будете ли вы склоняться к тому, что суперкар быстрее?
    А, если проводить тест не на шоссе, а на просёлочной дороге с ухабами?  ;)

    И вообще, научный метод (а я склонен считать себя его сторонником) предполагает сомнения ВО ВСЁМ, чего НЕ доказывают множественные независимые прозрачные тесты. И, даже, если доказывают, то всё равно нужно перепроверять иногда с новыми данными.
Изменено: Jack Famous - 31.05.2024 17:55:29
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, не докапываюсь, просто ваши "сомневаюсь" часто выглядят как утверждения с целью принизить чьи-то достижения.
"Вы там что-то создали? И что, хорошее? Ну, очень сомневаюсь... Наверняка это какая-то телега, а не McLaren Pro.  "
Про Ваш научный подход я помню, поэтому и странно читать про "сомневаюсь" без тестов. А вот про тесты было бы читать намного интереснее.
Ну и плюс вот такие странные посты бывают (раньше часто, сейчас очень редко).

И заметки то на самом деле не в упрёк, а по-дружески, как тёске :)
Изменено: nilske - 31.05.2024 17:55:29
 
Цитата
nilske: "Вы там что-то создали? И что, хорошее? Ну, очень сомневаюсь... Наверняка это какая-то телега, а не McLaren Pro.  "
не тот случай. С ноунеймами, которые "вундервафлю" состряпали — такое бывает. Приходится разоблачать мифы  :)

    А testuser мне сам ещё фору даст по некоторым вопросам — вот свежий пример. И он знает, что я его уважаю ♥  8)

Цитата
nilske: Ну и плюс вот  такие странные посты  бывают
тут ничего странного не вижу
Изменено: Jack Famous - 31.05.2024 17:55:30
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
И он знает, что я его уважаю
а вот уважать не надо сильно, это же все дилетантский уровень ). Вот настоящий уровень, например. Я взялся было портануть на vba, так для эксперимента, но денька через два бошка чет заболела, бросил короче это дело )
 
Цитата
написал: вот  свежий пример
Алексей, добрый день.
Алексей (testuser), наверняка знает, какая опасность в VBA кроется в манипуляциях указателями с помощью CopyMemory.
При отладке после любой ситуации, когда разные переменные указывают на один и тот же участок памяти, если в VBE нажать на сброс Run-Reset, то Excel аварийно закроется с потерей всего открытого в памяти. Например, в коде по ссылке на кибере поставь точку останова на ZeroMemory ByVal... , запусти тест и нажми Reset.
Как по мне, несмотря на API-преимущества, хуже возможности полного сбоя родительского приложения  (Excel) нет.
Поэтому такие опасные операции и производят во внешних скомпилированных DLL, о чем писал Виталий (BedVit).
Можно, конечно, чисто для себя аккуратно сделать VBA приложение с опасными манипуляциями памяти и не лезть в него больше, понимая опасность сбоя.
Изменено: ZVI - 31.05.2024 17:55:30
 
Цитата
testuser: это же все дилетантский уровень
всё относительно)
Держимся поближе к знатокам и жадно впитываем знания)
За ссылку спасибо — в тему (не эту). Разберу.

ZVI, привет)
Чтобы получить вылет нужно прям постараться, так что я не считаю это проблемой. Но обозначить этот момент (для людей "не в теме") нужно — спасибо, что это сделал 🤝
Изменено: Jack Famous - 31.05.2024 17:55:30
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
ZVI написал:
Алексей (testuser), наверняка знает, какая опасность в VBA кроется в манипуляциях указателями с помощью CopyMemory. При отладке после любой ситуации, когда разные переменные указывают на один и тот же участок памяти, если в VBE нажать на сброс Run-Reset, то Excel аварийно закроется с потерей всего открытого в памяти.
Да уж это просто та штука, которой выстрелили в ногу бейсику, тупой сборщик мусора, но бейсик, видимо на это и не рассчитывался будучи "бейсиком", даже учитывая гениальность его архитекторов..
Изменено: testuser - 01.06.2024 03:07:47
 
Цитата
testuser написал:
... не рассчитывался будучи "бейсиком"...
Такой сбой легко устроить в С и в C++, хоть там и заморочились безопасными аналогами функций и очисткой памяти. В Basic-e же принципиально ограничили беспредел в памяти, но не совсем - LSet остался и  VarPtr, ObjPtr, StrPtr.
Изменено: ZVI - 31.05.2024 17:55:30
 
ZVI, функции получения указателей недокументированы, насколько я помню) То есть, на свой страх и риск 😅
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
testuser написал:
Да уж это просто та штука, которой выстрелили в ногу бейсику, тупой сборщик мусора, но бейсик, видимо на это и не рассчитывался будучи "бейсиком", даже учитывая гениальность его архитекторов..

Бейсик здесь не причем. В любом ЯП есть штатные механизмы выделения и освобождения памяти. Если вы идете своим путем - будьте добры сами контролировать этот функционал (в Си/С+ в такой парадигме получите битые или висячие указатели, утечку памяти и в Шарпе сборщик мусора не поможет). Но за пробы пера плюсую, главное в прод не выводить, здесь полностью согласен с Владимиром (ZVI).

ZVI, Владимир, а если убрать зануление массивов в деструктор класса (VBA) (Class_Terminate())? что быстрее вызывается деструктор класса или очистка всех переменных модуля тестового кода? Будет ли в таком случае ошибка
Цитата
ZVI написал:
если в VBE нажать на сброс Run-Reset
Изменено: bedvit - 02.06.2024 10:22:45
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit написал:
(в Си/С+ в такой парадигме получите битые или висячие указатели, утечку памяти и в Шарпе сборщик мусора не поможет)
Владимир что-то говорил про безопасные аналоги функций и альтернативную процедуру очистки памяти, так я понял. Вот в VB6 подобного рода недочеты, на сколько помню, не вызывают падени всй IDE, видимо есть на это рассчет. Хотя он в сущности, использует тот же самый интерпретатор vba(vba6), но по всему есть какое-то более строгое разграничение между срдеой разработки и средой выполнеия
 
Цитата
bedvit написал:
что быстрее вызывается деструктор класса или очистка всех переменных модуля тестового кода? Будет ли в таком случае ошибка
Виталий, добрый день!
У автора(ов) темы проблем нет. Предупреждение о рисках увидели.
По сути вопроса - не проверял. Для меня достаточно надежного решения c DLL, или варианта с копированием ByVal, так как предпочитаю надежность каким-то абстрактным микросекундам выигрыша.
Изменено: ZVI - 04.06.2024 11:45:39
 
Цитата
ZVI написал:
каким-то абстрактным микросекундам выигрыша.
кто понял жизнь, тот больше не спешит 😁
Изменено: Msi2102 - 04.06.2024 18:27:01
 
ZVI, Владимир, спасибо за точку зрения. Надёжность всегда в приоритете, не поспоришь )
«Бритва Оккама» или «Принцип Калашникова»?
Страницы: 1
Наверх