例如,我有以下课程:
classdef testclass < handle
properties
buckets
end
methods
function tc = testclass(sz)
tc.buckets = cell(1, sz);
end
function put(tc,k)
tc.buckets{k}{1} = 1;
end
end
end
以下示例循环,我将性能与普通单元格数组进行比较:
tm = @java.lang.System.currentTimeMillis;
for N=[100 200 400 1000 2000 4000 8000]
tc = testclass(N);
Tstart = tm();
for k=1:N
tc.put(k);
end
Tend = tm();
fprintf(1, 'filling hash class (size %d): %d ms\n', N, Tend - Tstart);
arr = cell(1,N);
Tstart = tm();
for k=1:N
arr{k}{1} = 1;
end
Tend = tm();
fprintf(1, 'filling cell array (size %d): %d ms\n', N, Tend - Tstart);
end
输出结果为:
filling hash class (size 100): 8 ms
filling cell array (size 100): 0 ms
filling hash class (size 200): 9 ms
filling cell array (size 200): 0 ms
filling hash class (size 400): 24 ms
filling cell array (size 400): 1 ms
filling hash class (size 1000): 108 ms
filling cell array (size 1000): 2 ms
filling hash class (size 2000): 370 ms
filling cell array (size 2000): 5 ms
filling hash class (size 4000): 1396 ms
filling cell array (size 4000): 10 ms
filling hash class (size 8000): 5961 ms
filling cell array (size 8000): 21 ms
正如您所看到的,普通单元阵列表现出“线性”性能(这是预期的),但是包含在类中的数组会产生可怕的二次性能。
我在Matlab 2008a和Matlab 2010a上进行了测试。
是什么原因引起的?我该如何解决它?
答案 0 :(得分:3)
Matlab的真正力量仅适用于那些知道应该避免的人:)
解释语言中的OOP的一个主要问题(Matlab并不是唯一的)是调用方法所涉及的相当惊人的开销,正如您已经注意到的那样。 OOP在Matlab,Python等中需要与C ++,Fortran等完全不同的设计策略。
无论如何,你最好避免经常调用方法,并尽可能多地进行矢量化。
比较一下:
clc, clear classes
feature accel off % to make sure JIT doesn't throw things off
tm = @java.lang.System.currentTimeMillis;
for N = [100 200 400 1000 2000 4000 8000]
tc = testclass(N);
% call method inside loop
Tstart = tm();
for k=1:N
tc.put(k);
end
Tend = tm();
fprintf(1, 'filling hash class (loop, size %d) : %d ms\n', N, Tend - Tstart);
% call method only once
Tstart = tm();
tc.put(1:N);
Tend = tm();
fprintf(1, 'filling hash class (vectorized, size %d): %d ms\n', N, Tend - Tstart);
% cell-array direct assignment, looped version
arr = cell(1,N);
Tstart = tm();
for k=1:N
arr{k}{1} = 1;
end
Tend = tm();
fprintf(1, 'filling cell array (loop, size %d) : %d ms\n', N, Tend - Tstart);
% cell-array direct assignment, vectorized version
arr = cell(1,N);
Tstart = tm();
[arr{:}] = deal({1});
Tend = tm();
fprintf(1, 'filling cell array (vectorized, size %d): %d ms\n\n', N, Tend - Tstart);
end
其中testclass
中的相关方法被修改为处理矢量化和循环分配:
classdef testclass < handle
properties
buckets
end
methods
function tc = testclass(sz)
tc.buckets = cell(1, sz);
end
function put(tc,k)
[tc.buckets{k}] = deal({1});
end
end
end
结果:
filling hash class (loop, size 100) : 5 ms
filling hash class (vectorized, size 100): 0 ms
filling cell array (loop, size 100) : 0 ms
filling cell array (vectorized, size 100): 0 ms
filling hash class (loop, size 200) : 7 ms
filling hash class (vectorized, size 200): 0 ms
filling cell array (loop, size 200) : 0 ms
filling cell array (vectorized, size 200): 0 ms
filling hash class (loop, size 400) : 15 ms
filling hash class (vectorized, size 400): 1 ms
filling cell array (loop, size 400) : 1 ms
filling cell array (vectorized, size 400): 0 ms
filling hash class (loop, size 1000) : 36 ms
filling hash class (vectorized, size 1000): 2 ms
filling cell array (loop, size 1000) : 2 ms
filling cell array (vectorized, size 1000): 1 ms
filling hash class (loop, size 2000) : 73 ms
filling hash class (vectorized, size 2000): 2 ms
filling cell array (loop, size 2000) : 4 ms
filling cell array (vectorized, size 2000): 2 ms
filling hash class (loop, size 4000) : 145 ms
filling hash class (vectorized, size 4000): 5 ms
filling cell array (loop, size 4000) : 9 ms
filling cell array (vectorized, size 4000): 4 ms
filling hash class (loop, size 8000) : 292 ms
filling hash class (vectorized, size 8000): 8 ms
filling cell array (loop, size 8000) : 18 ms
filling cell array (vectorized, size 8000): 9 ms
答案 1 :(得分:0)
是什么原因引起的?我该如何解决它?
减速是使用对象的结果。对象以程序员的身份为您买单,但是,它们涉及开销。如果不放弃对象,就无法绕过这种开销。根据语言和您的特定实现,开销将是微不足道或实质性的。
我写了一个简单的C ++程序,它创建了一个带有成员数组和裸数组的对象。填充对象内部的数组比填充裸阵列要长得多。
#include <iostream>
#include <ctime>
static const int MAX_SIZE = 1000000;
class Holder{
public:
void putValue(int val, int idx);
private:
int data[MAX_SIZE];
};
void Holder::putValue(int v, int i){
data[i] = v;
}
int main(int argc, char **argv){
Holder h;
int data[MAX_SIZE];
int j, i;
clock_t begin, end;
int outerLoop = 200;
fprintf(stderr,"Testing array in object!\n");
begin = clock();
for ( j=0; j<outerLoop; j++)
for ( i = 0; i<MAX_SIZE; i++)
h.putValue(i,i);
end = clock();
fprintf(stderr,"Done! El time:%3.3f\n", double(end - begin)/CLOCKS_PER_SEC);
fprintf(stderr,"Testing naked array 2!\n");
begin = clock();
for ( j=0; j<outerLoop; j++)
for ( i = 0; i<MAX_SIZE; i++)
data[i] = i;
end = clock();
fprintf(stderr,"Done! El time:%3.3f\n", double(end - begin)/CLOCKS_PER_SEC);
}
这是输出:
在对象中测试数组!
完成!时间:1.413
测试裸阵列2!
完成!时间:0.690