Страницы: 1
RSS
Скорость работы пользовательских функций, возвращающих несколько значений
 
Столкнулся со следующей проблемой:  
при многократном использовании пользовательской функции, возвращающей массив значений, эксель начинает критически тормозить.    
Аналогичный алгоритм, написанный на листе с помощью формул эксель не тормозит.  
 
Какие есть варианты по оптимизации: ускорение вызова действующей функции или другое решение?
 
Уберите Application.Volatile True
 
{quote}{login=Казанский}{date=22.12.2010 05:55}{thema=}{post}Уберите Application.Volatile True{/post}{/quote}  
 
Пробовал и Application.Volatile False и вообще без употребления Application.Volatile, работает немножко быстрее, но всё равно очень медленно.  
 
Сама функция очень простая, я не вижу, что можно оптимизировать в ней. Причина в многократном вызове. Может ее можно "вшить" в ексель, что бы он ее воспринимал как "родную"?
 
оптимизировать как раз есть что:  
 
Function SpeedTest(inp1 As Double, inp2 As Double, inp3 As Double) As Variant  
 
Application.Volatile True  
 
Dim result(1 To 10) As Double  
Dim i As Long  
 
result(i) = inp1 + inp2 + inp3  
For i = 2 To 10  
     
   result(i) = result(i - 1) + result(1)  
 
Next i  
 
SpeedTest = result  
 
End Function
Живи и дай жить..
 
слэн,  
нет, практически не меняется. И так тоже:  
 
Function SpeedTest1(inp1 As Double, inp2 As Double, inp3 As Double) As Variant  
Application.Volatile True  
Dim result(1 To 10) As Double  
Dim i As Long, inp As Double  
inp = inp1 + inp2 + inp3  
For i = 1 To 10  
result(i) = i * inp  
Next i  
SpeedTest1 = result  
End Function  
 
makchu,  
для того, чтобы выложить на лист массив значений, возвращаемый функцией, совсем не нужно извлекать их с помощью ИНДЕКС. Нужно просто вводить формулу в диапазон как формулу массива. Соответственно, ф-я будет вызываться в 10 раз реже (по числу значений). Попробуйте - торможения практически нет:
 
Можно написать ф-ю так, чтобы она сразу возвращала "вертикальный" массив.  
Однако, ускорения это вроде бы не дает:
 
{quote}{login=Казанский}{date=22.12.2010 07:06}{thema=}{post}слэн,  
нет, практически не меняется. И так тоже:  
 
Function SpeedTest1(inp1 As Double, inp2 As Double, inp3 As Double) As Variant  
Application.Volatile True  
Dim result(1 To 10) As Double  
Dim i As Long, inp As Double  
inp = inp1 + inp2 + inp3  
For i = 1 To 10  
result(i) = i * inp  
Next i  
SpeedTest1 = result  
End Function  
 
makchu,  
для того, чтобы выложить на лист массив значений, возвращаемый функцией, совсем не нужно извлекать их с помощью ИНДЕКС. Нужно просто вводить формулу в диапазон как формулу массива. Соответственно, ф-я будет вызываться в 10 раз реже (по числу значений). Попробуйте - торможения практически нет:{/post}{/quote}  
 
Спасибо! Да, с транспонированием работает побыстрее :) но у всё ещё сильно тормозит. Комп слабый.  
Я тело функции для примера привёл, в реальности оно другое, там несколько условий и простые вычисления.    
 
А создание надстроек не поможет делу? Ведь встроенные функции екселя работают заметно быстрее.
 
Я так полагаю, пример функции приведён чисто условный. Оптимизировать саму функцию смысла нет. Можно вообще сделать так:  
 
Function SpeedTest(inp1 As Double, inp2 As Double, inp3 As Double)  
 SpeedTest = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  
End Function  
 
и разница в скорости будет практически не заметна.  
Тут уже дело в скорости вызова самой пользовательской функуии, что для экселя оставляет желать лучшего. Если UDF вводится в большой диапазон ячеек - сразу появляются "тормоза", какая бы простая она ни была. Скорость вызова UDF можно приравнять к скорости перебора по ячейкам листа. При чём, даже если ей не передавать ни один параметр:  
Function SpeedTest()  
 SpeedTest = 1  
End Function  
(Естественно, вызывать её нужно тоже без пераметров).  
 
Это и есть та ложка дёгтя в бочке мёда! Такая полезная вещь, как пользовательские функции, иногда неприемлемы из-за своей скорости вызова.    
Мой вопрос заключается в том, можно ли вызвать внешнюю функцию, находящуюся в dll, не заходя в VBA, а сразу обратиться к сторонней библиотеке ? Может быть это можно сделать как-то через Excel Macro 4 ?
 
{quote}{login=Казанский}{date=22.12.2010 07:19}{thema=}{post}Можно написать ф-ю ...{/post}{/quote}ф-ю = Фак ю ? :-)
 
{quote}{login=@Nik}{date=22.12.2010 07:54}{thema=}{post} Может быть это можно сделать как-то через Excel Macro 4 ?{/post}{/quote}  
Что уж, лучше сразу в Python через COM сделать.
 
> можно ли вызвать внешнюю функцию, находящуюся в dll, не заходя в VBA, а сразу обратиться к сторонней библиотеке ?  
 
См. функцию ВЫЗВАТЬ
 
Не понимаю.  
 
Придумать "гомункулуса":  
-------------------  
Function SpeedTest(inp1 As Double, inp2 As Double, inp3 As Double) As Variant  
Application.Volatile True  
Dim result(1 To 10) As Double  
Dim i As Integer  
For i = 1 To 10  
   result(i) = i * (inp1 + inp2 + inp3)  
Next i  
SpeedTest = result  
End Function  
-------------------  
с Volatile = True,  
на листе засунуть его в ИНДЕКС(SpeedTest(D$8;D$9;D$10);$B14)  (нахрена тогда делать "пользовательскую функцию, возвращающую несколько значений")  
растянуть формулы на пол-листа,  
а потом начать орать: "эксель начинает критически тормозить."
 
{quote}{login=@Nik}{date=22.12.2010 07:54}{thema=}{post}Я так полагаю, пример функции приведён чисто условный. Оптимизировать саму функцию смысла нет. Можно вообще сделать так:  
 
Function SpeedTest(inp1 As Double, inp2 As Double, inp3 As Double)  
 SpeedTest = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  
End Function  
 
и разница в скорости будет практически не заметна.  
Тут уже дело в скорости вызова самой пользовательской функуии, что для экселя оставляет желать лучшего. Если UDF вводится в большой диапазон ячеек - сразу появляются "тормоза", какая бы простая она ни была. Скорость вызова UDF можно приравнять к скорости перебора по ячейкам листа. При чём, даже если ей не передавать ни один параметр:  
Function SpeedTest()  
 SpeedTest = 1  
End Function  
(Естественно, вызывать её нужно тоже без пераметров).  
 
Это и есть та ложка дёгтя в бочке мёда! Такая полезная вещь, как пользовательские функции, иногда неприемлемы из-за своей скорости вызова.    
Мой вопрос заключается в том, можно ли вызвать внешнюю функцию, находящуюся в dll, не заходя в VBA, а сразу обратиться к сторонней библиотеке ? Может быть это можно сделать как-то через Excel Macro 4 ?{/post}{/quote}  
 
Да, совершенно верно! Пример функции чисто условный! Проблема в медленном вызове ЮДФ при многократном использовании.
 
{quote}{login=Казанский}{date=22.12.2010 11:12}{thema=}{post}> можно ли вызвать внешнюю функцию, находящуюся в dll, не заходя в VBA, а сразу обратиться к сторонней библиотеке ?  
 
См. функцию ВЫЗВАТЬ{/post}{/quote}  
 
Использование функции ВЫЗВАТЬ предаст реальное ускорение вызову ЮДФ или это гипотеза? :)    
Я это к тому, что dll делать не умею и если не будет ощутимого эффекта, то разбираться с библиотеками не хотелось бы .
 
Предыдущие посты мои :))  
 
Нашёл временное решение:  
не растягивать одномерный массив вправо а создать функцию, которая сразу возвращает двумерный массив. На лист вгонять его с помощью ТРАНСП и контр+шифт+энтер :)))) работает существенно быстрее. в бэйсик происходит одно обращение на весь массив.
 
{quote}{login=makchu}{date=23.12.2010 10:38}{thema=}{post}  
работает существенно быстрее{/post}{/quote}  
Вот можно-же ограничится "административным мерами", зачем сразу приговаривать к "высшей". :)
 
{quote}{login=}Использование функции ВЫЗВАТЬ предаст реальное ускорение вызову ЮДФ или это гипотеза? :)    
Я это к тому, что dll делать не умею и если не будет ощутимого эффекта, то разбираться с библиотеками не хотелось бы .{/post}{/quote}  
 
Использование VSTO даст, но в вашем случае нужно обойтись без формул, только VBA.
 
Что такое "VSTO" и что даст его использование ?
Страницы: 1
Читают тему
Наверх