MATLAB OOP работает медленно или я что-то не так делаю?

Атрибуты являются, по существу, битами данных, которые Вы хотите присоединить к Вашему типы (классы, методы, события, перечисления, и т.д.)

, идея состоит в том, что во время выполнения некоторый другой тип/платформа/инструмент будет запрашивать Ваш тип для получения информации в атрибуте и реагировать на них.

Так, например, Visual Studio может запросить атрибуты на стороннем управлении для выяснения, какие свойства управления должны появиться в области Properties во время проектирования.

Атрибуты могут также использоваться в Аспектно-ориентированном программировании для введения/управления объектов во время выполнения на основе атрибутов, которые украшают их и добавляют проверку, вход, и т.д. к объектам, не влияя на бизнес-логику объекта.

136
задан Jonas Stein 30 October 2017 в 17:30
поделиться

2 ответа

Некоторое время я работал с OO MATLAB и в конце концов обнаружил похожие проблемы с производительностью.

Короткий ответ: да, ООП MATLAB работает медленно. Существуют значительные накладные расходы на вызов методов, более высокие, чем у основных объектно-ориентированных языков, и с этим мало что можно сделать. Частично причина может заключаться в том, что идиоматический MATLAB использует "векторизованный" код для уменьшения количества вызовов методов, а накладные расходы на каждый вызов не являются высоким приоритетом.

Я проверил производительность, написав ничего не делающие "nop" функции как различные типы функций и методов. Вот некоторые типичные результаты.

>> call_nops
Computer: PCWIN   Release: 2009b
Calling each function/method 100000 times
nop() function:                 0.02261 sec   0.23 usec per call
nop1-5() functions:             0.02182 sec   0.22 usec per call
nop() subfunction:              0.02244 sec   0.22 usec per call
@()[] anonymous function:       0.08461 sec   0.85 usec per call
nop(obj) method:                0.24664 sec   2.47 usec per call
nop1-5(obj) methods:            0.23469 sec   2.35 usec per call
nop() private function:         0.02197 sec   0.22 usec per call
classdef nop(obj):              0.90547 sec   9.05 usec per call
classdef obj.nop():             1.75522 sec  17.55 usec per call
classdef private_nop(obj):      0.84738 sec   8.47 usec per call
classdef nop(obj) (m-file):     0.90560 sec   9.06 usec per call
classdef class.staticnop():     1.16361 sec  11.64 usec per call
Java nop():                     2.43035 sec  24.30 usec per call
Java static_nop():              0.87682 sec   8.77 usec per call
Java nop() from Java:           0.00014 sec   0.00 usec per call
MEX mexnop():                   0.11409 sec   1.14 usec per call
C nop():                        0.00001 sec   0.00 usec per call

Аналогичные результаты для R2008a - R2009b. Это в Windows XP x64 с 32-разрядной версией MATLAB.

"Java nop ()" - это бездействующий Java-метод, вызываемый из цикла M-кода, и включает накладные расходы на отправку MATLAB-to-Java с каждым вызовом. «Java nop () from Java» - это то же самое, что вызывается в цикле Java for (), и не влечет за собой штраф за границу. Возьмите тайминги Java и C с недоверием; умный компилятор может полностью оптимизировать вызовы.

Механизм определения области видимости пакета является новым и представлен примерно в то же время, что и классы classdef. Его поведение может быть связано.

Несколько предварительных выводов:

  • Методы медленнее, чем функции.
  • Методы нового стиля (classdef) медленнее, чем методы старого стиля.
  • Новый obj.nop () Синтаксис медленнее, чем синтаксис nop (obj) , даже для того же метода в объекте classdef. То же самое для объектов Java (не показаны). Если вы хотите действовать быстро, позвоните по номеру nop (obj) .
  • Накладные расходы на вызов метода выше (примерно в 2 раза) в 64-битном MATLAB в Windows. (Не показано.)
  • Отправка метода MATLAB происходит медленнее, чем в некоторых других языках.

Сказать, почему это так, было бы только предположением с моей стороны. Внутренние объекты OO механизма MATLAB не являются общедоступными. Сама по себе проблема не интерпретируемая и скомпилированная - в MATLAB есть JIT, - но более свободная типизация и синтаксис MATLAB могут означать больше работы во время выполнения. (Например, вы не можете определить только по синтаксису, является ли «f (x)» вызовом функции или индексом в массиве; это зависит от состояния рабочей области во время выполнения.) Это может быть потому, что определения классов MATLAB связаны в состояние файловой системы, чего не делают многие другие языки.

Итак, что делать?

Идиоматический подход MATLAB к этому - "векторизация" ваш код, структурируя определения ваших классов так, чтобы экземпляр объекта был оболочкой для массива; то есть каждое из его полей содержит параллельные массивы (называемые «плоской» организацией в документации MATLAB). Вместо того, чтобы иметь массив объектов, каждое из которых содержит поля, содержащие скалярные значения, определяют объекты, которые сами по себе являются массивами, а методы принимают массивы в качестве входных данных и выполняют векторизованные вызовы полей и входов. Это уменьшает количество выполняемых вызовов методов, достаточно надеяться, что накладные расходы на отправку не являются узким местом.

Имитация класса C ++ или Java в MATLAB, вероятно, не будет оптимальной. Классы Java / C ++ обычно строятся так, что объекты являются наименьшими строительными блоками, настолько конкретными, насколько это возможно (то есть множеством разных классов), и вы составляете их в массивы, объекты коллекции и т. Д. И перебираете их с помощью циклов. Чтобы сделать классы MATLAB быстрыми, выверните этот подход наизнанку. Создавайте классы большего размера, поля которых являются массивами, и вызывайте векторизованные методы для этих массивов.

Смысл в том, чтобы организовать ваш код таким образом, чтобы он использовал сильные стороны языка - обработку массивов, векторизованную математику - и избегал слабых мест. РЕДАКТИРОВАТЬ: С момента первоначального сообщения вышли R2010b и R2011a. Общая картина такая же: вызовы MCOS становятся немного быстрее, а вызовы методов Java и старого стиля становятся медленнее .

РЕДАКТИРОВАТЬ: Раньше у меня были некоторые заметки о «чувствительности пути» с дополнительная таблица таймингов вызовов функций, где на время функций влияло то, как был настроен путь Matlab, но, похоже, это было отклонением от моей конкретной настройки сети в то время. В приведенной выше таблице отражены времена, характерные для преобладания моих тестов с течением времени.

Обновление: R2011b

РЕДАКТИРОВАТЬ (2/13/2012): R2011b отсутствует, и картина производительности изменилась достаточно, чтобы обновить это.

Arch: PCWIN   Release: 2011b 
Machine: R2011b, Windows XP, 8x Core i7-2600 @ 3.40GHz, 3 GB RAM, NVIDIA NVS 300
Doing each operation 100000 times
style                           total       µsec per call
nop() function:                 0.01578      0.16
nop(), 10x loop unroll:         0.01477      0.15
nop(), 100x loop unroll:        0.01518      0.15
nop() subfunction:              0.01559      0.16
@()[] anonymous function:       0.06400      0.64
nop(obj) method:                0.28482      2.85
nop() private function:         0.01505      0.15
classdef nop(obj):              0.43323      4.33
classdef obj.nop():             0.81087      8.11
classdef private_nop(obj):      0.32272      3.23
classdef class.staticnop():     0.88959      8.90
classdef constant:              1.51890     15.19
classdef property:              0.12992      1.30
classdef property with getter:  1.39912     13.99
+pkg.nop() function:            0.87345      8.73
+pkg.nop() from inside +pkg:    0.80501      8.05
Java obj.nop():                 1.86378     18.64
Java nop(obj):                  0.22645      2.26
Java feval('nop',obj):          0.52544      5.25
Java Klass.static_nop():        0.35357      3.54
Java obj.nop() from Java:       0.00010      0.00
MEX mexnop():                   0.08709      0.87
C nop():                        0.00001      0.00
j() (builtin):                  0.00251      0.03

Я думаю, что результатом этого является следующее:

  • Методы MCOS / classdef работают быстрее. Стоимость сейчас примерно равна стоимости классов старого стиля, если вы используете синтаксис foo (obj) . Таким образом, скорость метода больше не является причиной в большинстве случаев придерживаться классов старого стиля. (Престижность, MathWorks!)
  • Размещение функций в пространствах имен замедляет их работу. (Не новинка в R2011b, просто новинка в моем тесте.)

Обновление: R2014a

Я реконструировал код тестирования и запустил его на R2014a.

Matlab R2014a on PCWIN64  
Matlab 8.3.0.532 (R2014a) / Java 1.7.0_11 on PCWIN64 Windows 7 6.1 (eilonwy-win7) 
Machine: Core i7-3615QM CPU @ 2.30GHz, 4 GB RAM (VMware Virtual Platform)
nIters = 100000 

Operation                        Time (µsec)  
nop() function:                         0.14 
nop() subfunction:                      0.14 
@()[] anonymous function:               0.69 
nop(obj) method:                        3.28 
nop() private fcn on @class:            0.14 
classdef nop(obj):                      5.30 
classdef obj.nop():                    10.78 
classdef pivate_nop(obj):               4.88 
classdef class.static_nop():           11.81 
classdef constant:                      4.18 
classdef property:                      1.18 
classdef property with getter:         19.26 
+pkg.nop() function:                    4.03 
+pkg.nop() from inside +pkg:            4.16 
feval('nop'):                           2.31 
feval(@nop):                            0.22 
eval('nop'):                           59.46 
Java obj.nop():                        26.07 
Java nop(obj):                          3.72 
Java feval('nop',obj):                  9.25 
Java Klass.staticNop():                10.54 
Java obj.nop() from Java:               0.01 
MEX mexnop():                           0.91 
builtin j():                            0.02 
struct s.foo field access:              0.14 
isempty(persistent):                    0.00 

Обновление: R2015b: объекты стали быстрее!

Вот Результаты R2015b, любезно предоставленные @Shaked. Это большое изменение: ООП значительно быстрее, и теперь синтаксис obj.method () так же быстр, как метод (obj) , и намного быстрее, чем унаследованные объекты ООП.

Matlab R2015b on PCWIN64  
Matlab 8.6.0.267246 (R2015b) / Java 1.7.0_60 on PCWIN64 Windows 8 6.2 (nanit-shaked) 
Machine: Core i7-4720HQ CPU @ 2.60GHz, 16 GB RAM (20378)
nIters = 100000 

Operation                        Time (µsec)  
nop() function:                         0.04 
nop() subfunction:                      0.08 
@()[] anonymous function:               1.83 
nop(obj) method:                        3.15 
nop() private fcn on @class:            0.04 
classdef nop(obj):                      0.28 
classdef obj.nop():                     0.31 
classdef pivate_nop(obj):               0.34 
classdef class.static_nop():            0.05 
classdef constant:                      0.25 
classdef property:                      0.25 
classdef property with getter:          0.64 
+pkg.nop() function:                    0.04 
+pkg.nop() from inside +pkg:            0.04 
feval('nop'):                           8.26 
feval(@nop):                            0.63 
eval('nop'):                           21.22 
Java obj.nop():                        14.15 
Java nop(obj):                          2.50 
Java feval('nop',obj):                 10.30 
Java Klass.staticNop():                24.48 
Java obj.nop() from Java:               0.01 
MEX mexnop():                           0.33 
builtin j():                            0.15 
struct s.foo field access:              0.25 
isempty(persistent):                    0.13 

Обновление: R2018a

Вот результаты R2018a . Это не тот огромный скачок, который мы наблюдали, когда в R2015b был представлен новый механизм исполнения, но это все же заметное улучшение из года в год. Примечательно, что обработка анонимных функций стала намного быстрее.

Matlab R2018a on MACI64  
Matlab 9.4.0.813654 (R2018a) / Java 1.8.0_144 on MACI64 Mac OS X 10.13.5 (eilonwy) 
Machine: Core i7-3615QM CPU @ 2.30GHz, 16 GB RAM 
nIters = 100000 

Operation                        Time (µsec)  
nop() function:                         0.03 
nop() subfunction:                      0.04 
@()[] anonymous function:               0.16 
classdef nop(obj):                      0.16 
classdef obj.nop():                     0.17 
classdef pivate_nop(obj):               0.16 
classdef class.static_nop():            0.03 
classdef constant:                      0.16 
classdef property:                      0.13 
classdef property with getter:          0.39 
+pkg.nop() function:                    0.02 
+pkg.nop() from inside +pkg:            0.02 
feval('nop'):                          15.62 
feval(@nop):                            0.43 
eval('nop'):                           32.08 
Java obj.nop():                        28.77 
Java nop(obj):                          8.02 
Java feval('nop',obj):                 21.85 
Java Klass.staticNop():                45.49 
Java obj.nop() from Java:               0.03 
MEX mexnop():                           3.54 
builtin j():                            0.10 
struct s.foo field access:              0.16 
isempty(persistent):                    0.07 

Обновление: R2018b и R2019a: Без изменений

Без существенных изменений. Я не утруждаю себя включением результатов тестирования.

Исходный код для тестов

Я поместил исходный код для этих тестов на GitHub, выпущенный под лицензией MIT. https://github.com/apjanke/matlab-bench

218
ответ дан 23 November 2019 в 23:40
поделиться

У класса дескриптора есть дополнительные накладные расходы, связанные с отслеживанием всех ссылок на себя в целях очистки.

Попробуйте тот же эксперимент без использования класса дескриптора и посмотрите, каковы ваши результаты.

3
ответ дан 23 November 2019 в 23:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: