matlab InputParser vs exist(...,'var ')vs nargin性能

eblbsuwk  于 6个月前  发布在  Matlab
关注(0)|答案(2)|浏览(49)

这三种变体在输入检查/默认初始化方面是否有任何性能比较?
比较一下最近的版本,例如R2014 b和旧版本的R2012 b是有用的。
一个例子:

function foo(a,b)
  if nargin < 1, a = 1; end
  if nargin < 2, b = 2; end
end

versus

function foo(a,b)
  if exist('a','var'), a = 1; end
  if exist('b','var'), b = 2; end
end

versus 

function foo(varargin)
  p = inputParser;
  addOptional(p,'a',1)
  addOptional(p,'b',2)
  parse(p,varargin{:})
end

字符串
在R2014 b上使用Amro的测试套件:

func           nargs       time   
_________________    _____    __________
'foo_nargin'         0        2.3674e-05
'foo_exist'          0        3.1339e-05
'foo_inputparser'    0        9.6934e-05
'foo_nargin'         1        2.4437e-05
'foo_exist'          1        3.2157e-05
'foo_inputparser'    1         0.0001307
'foo_nargin'         2        2.3838e-05
'foo_exist'          2        3.0492e-05
'foo_inputparser'    2        0.00015775

hyrbngr7

hyrbngr71#

下面是一些代码来测试这三种方法:

function t = testArgParsing()
    args = {1, 2};
    fcns = {
        @foo_nargin ;
        @foo_exist ;
        @foo_inputparser
    };

    % parameters sweep
    [f,k] = ndgrid(1:numel(fcns), 0:numel(args));
    f = f(:); k = k(:);

    % test combinations of functions and number of input args
    t = cell(numel(f), 3);
    for i=1:size(t,1)
        t{i,1} = func2str(fcns{f(i)});
        t{i,2} = k(i);
        t{i,3} = timeit(@() feval(fcns{f(i)}, args{1:k(i)}), 2);
    end

    % format results in table
    t = cell2table(t, 'VariableNames',{'func','nargs','time'});
end

function [aa,bb] = foo_nargin(a,b)
  if nargin < 1, a = 1; end
  if nargin < 2, b = 2; end
  aa = a;
  bb = b;
end

function [aa,bb] = foo_exist(a,b)
  if ~exist('a','var'), a = 1; end
  if ~exist('b','var'), b = 2; end
  aa = a;
  bb = b;
end

function [aa,bb] = foo_inputparser(varargin)
  p = inputParser;
  addOptional(p,'a',1);
  addOptional(p,'b',2);
  parse(p, varargin{:});
  aa = p.Results.a;
  bb = p.Results.b;
end

字符串
以下是我在R2014a中获得的内容:

>> t = testArgParsing
t = 
          func           nargs       time   
    _________________    _____    __________
    'foo_nargin'         0        3.4556e-05
    'foo_exist'          0        5.2901e-05
    'foo_inputparser'    0        0.00010254
    'foo_nargin'         1        2.5531e-05
    'foo_exist'          1        3.7105e-05
    'foo_inputparser'    1         0.0001263
    'foo_nargin'         2        2.4991e-05
    'foo_exist'          2        3.6772e-05
    'foo_inputparser'    2        0.00015148


和一个漂亮的情节来查看结果:

tt = unstack(t, 'time', 'func');
names = tt.Properties.VariableNames(2:end);
bar(tt{:,2:end}.')
set(gca, 'XTick',1:numel(names), 'XTickLabel',names, 'YGrid','on')
legend(num2str(tt{:,1}, 'nargin=%d'))
ylabel('Time [sec]'), xlabel('Functions')


的数据

flvlnr44

flvlnr442#

我在2023 b上重新运行了Amro的测试,做了一些修改:

  • 使用2019年引入的函数参数验证添加函数b
  • 添加了更多可选的输入参数
  • 删除函数输出分配
  • 对函数调用运行timeit 5000次
  • 增加了inputParser的一个变体,其中在访问值之前将p.results从嵌套结构中取出。

Time Comparison Bar Plot

function t = testArgParsing()
args = {0, 2, 5, 10, 15};
fcns = {
    @foo_nargin ;
    @foo_exist ;
    @foo_inputparser ;
    @foo_inputparser_struct ;
    @foo_argument ;
    @foo_argument_opt ;
};

% parameters sweep
[f,k] = ndgrid(1:numel(fcns), cell2mat(args));
f = f(:); k = k(:);
% test combinations of functions and number of input args
t = cell(numel(f), 3);
for i=1:size(t,1)
    t{i,1} = func2str(fcns{f(i)});
    t{i,2} = k(i);
    if isequal(fcns{f(i)}, @foo_argument_opt)
        if k(i) >= 0; opt = struct; end
        if k(i) >= 1; opt.a01 = 1; end
        if k(i) >= 2; opt.a02 = 2; end
        if k(i) >= 3; opt.a03 = 3; end
        if k(i) >= 4; opt.a04 = 4; end
        if k(i) >= 5; opt.a05 = 5; end
        if k(i) >= 6; opt.a06 = 6; end
        if k(i) >= 7; opt.a07 = 7; end
        if k(i) >= 8; opt.a08 = 8; end
        if k(i) >= 9; opt.a09 = 9; end
        if k(i) >= 10; opt.a10 = 10; end
        if k(i) >= 11; opt.a11 = 11; end
        if k(i) >= 12; opt.a12 = 12; end
        if k(i) >= 13; opt.a13 = 13; end
        if k(i) >= 14; opt.a14 = 14; end
        if k(i) >= 15; opt.a15 = 15; end
        cellArgs = namedargs2cell(opt);
    else
        cellArgs = num2cell(1:k(i));
    end
    t{i,3} = timeit(@() foo_nrun(fcns{f(i)}, cellArgs));
end
% format results in table
t = cell2table(t, 'VariableNames',{'func','nargs','time'});
end

function foo_nrun(fcn,cellArgs)
    nrun = 5000;
    for i = 1:nrun
        feval(fcn, cellArgs{:});
    end
end

function foo_nargin(a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15)
if nargin < 1, a01 = 1; end
if nargin < 2, a02 = 2; end
if nargin < 3, a03 = 3; end
if nargin < 4, a04 = 4; end
if nargin < 5, a05 = 5; end
if nargin < 6, a06 = 6; end
if nargin < 7, a07 = 7; end
if nargin < 8, a08 = 8; end
if nargin < 9, a09 = 9; end
if nargin < 10, a10 = 10; end
if nargin < 11, a11 = 11; end
if nargin < 12, a12 = 12; end
if nargin < 13, a13 = 13; end
if nargin < 14, a14 = 14; end
if nargin < 15, a15 = 15; end
a01;
a02;
a03;
a04;
a05;
a06;
a07;
a08;
a09;
a10;
a11;
a12;
a13;
a14;
a15;
end

function foo_exist(a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15)
if ~exist('a01','var'), a01 = 1; end
if ~exist('a02','var'), a02 = 2; end
if ~exist('a03','var'), a03 = 3; end
if ~exist('a04','var'), a04 = 4; end
if ~exist('a05','var'), a05 = 5; end
if ~exist('a06','var'), a06 = 6; end
if ~exist('a07','var'), a07 = 7; end
if ~exist('a08','var'), a08 = 8; end
if ~exist('a09','var'), a09 = 9; end
if ~exist('a10','var'), a10 = 10; end
if ~exist('a11','var'), a11 = 11; end
if ~exist('a12','var'), a12 = 12; end
if ~exist('a13','var'), a13 = 13; end
if ~exist('a14','var'), a14 = 14; end
if ~exist('a15','var'), a15 = 15; end
a01;
a02;
a03;
a04;
a05;
a06;
a07;
a08;
a09;
a10;
a11;
a12;
a13;
a14;
a15;
end

function foo_inputparser(varargin)
p = inputParser;
addOptional(p,'a01',1);
addOptional(p,'a02',2);
addOptional(p,'a03',3);
addOptional(p,'a04',4);
addOptional(p,'a05',5);
addOptional(p,'a06',6);
addOptional(p,'a07',7);
addOptional(p,'a08',8);
addOptional(p,'a09',9);
addOptional(p,'a10',10);
addOptional(p,'a11',11);
addOptional(p,'a12',12);
addOptional(p,'a13',13);
addOptional(p,'a14',14);
addOptional(p,'a15',15);
parse(p, varargin{:});
p.Results.a01;
p.Results.a02;
p.Results.a03;
p.Results.a04;
p.Results.a05;
p.Results.a06;
p.Results.a07;
p.Results.a08;
p.Results.a09;
p.Results.a10;
p.Results.a11;
p.Results.a12;
p.Results.a13;
p.Results.a14;
p.Results.a15;

end

function foo_inputparser_struct(varargin)
p = inputParser;
addOptional(p,'a01',1);
addOptional(p,'a02',2);
addOptional(p,'a03',3);
addOptional(p,'a04',4);
addOptional(p,'a05',5);
addOptional(p,'a06',6);
addOptional(p,'a07',7);
addOptional(p,'a08',8);
addOptional(p,'a09',9);
addOptional(p,'a10',10);
addOptional(p,'a11',11);
addOptional(p,'a12',12);
addOptional(p,'a13',13);
addOptional(p,'a14',14);
addOptional(p,'a15',15);
parse(p, varargin{:});
tmp = p.Results;
tmp.a01;
tmp.a02;
tmp.a03;
tmp.a04;
tmp.a05;
tmp.a06;
tmp.a07;
tmp.a08;
tmp.a09;
tmp.a10;
tmp.a11;
tmp.a12;
tmp.a13;
tmp.a14;
tmp.a15;
end

function foo_argument(a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15)
arguments
    a01 = 1
    a02 = 2
    a03 = 3
    a04 = 4
    a05 = 5
    a06 = 6
    a07 = 7
    a08 = 8
    a09 = 9
    a10 = 10
    a11 = 11
    a12 = 12
    a13 = 13
    a14 = 14
    a15 = 15
end
a01;
a02;
a03;
a04;
a05;
a06;
a07;
a08;
a09;
a10;
a11;
a12;
a13;
a14;
a15;
end

function foo_argument_opt(opt)
arguments
    opt.a01 = 1
    opt.a02 = 2
    opt.a03 = 3
    opt.a04 = 4
    opt.a05 = 5
    opt.a06 = 6
    opt.a07 = 7
    opt.a08 = 8
    opt.a09 = 9
    opt.a10 = 10
    opt.a11 = 11
    opt.a12 = 12
    opt.a13 = 13
    opt.a14 = 14
    opt.a15 = 15
end
opt.a01;
opt.a02;
opt.a03;
opt.a04;
opt.a05;
opt.a06;
opt.a07;
opt.a08;
opt.a09;
opt.a10;
opt.a11;
opt.a12;
opt.a13;
opt.a14;
opt.a15;
end
t = testArgParsing()

tt = unstack(t, 'time', 'func');
names = tt.Properties.VariableNames(2:end);
bar(tt{:,2:end}.')
set(gca, 'XTick',1:numel(names), 'XTickLabel',names, 'YGrid','on','TickLabelInterpreter','None')
legend(num2str(tt{:,1}, 'nargin=%d'),'Location','northwest')
ylabel('Time [sec]'), xlabel('Functions')
set(gca, 'YScale', 'log')
t =

  30×3 table

               func               nargs       time   
    __________________________    _____    __________

    {'foo_nargin'            }      0      0.00033001
    {'foo_exist'             }      0         0.08243
    {'foo_inputparser'       }      0          0.5845
    {'foo_inputparser_struct'}      0         0.21552
    {'foo_argument'          }      0      0.00050585
    {'foo_argument_opt'      }      0        0.027147
    {'foo_nargin'            }      2      0.00058672
    {'foo_exist'             }      2        0.083175
    {'foo_inputparser'       }      2         0.55961
    {'foo_inputparser_struct'}      2          0.2141
    {'foo_argument'          }      2      0.00056622
    {'foo_argument_opt'      }      2        0.035206
    {'foo_nargin'            }      5      0.00072787
    {'foo_exist'             }      5        0.083359
    {'foo_inputparser'       }      5         0.58168
    {'foo_inputparser_struct'}      5         0.22248
    {'foo_argument'          }      5      0.00074445
    {'foo_argument_opt'      }      5        0.047712
    {'foo_nargin'            }     10       0.0010616
    {'foo_exist'             }     10        0.083944
    {'foo_inputparser'       }     10         0.58553
    {'foo_inputparser_struct'}     10         0.23748
    {'foo_argument'          }     10       0.0011567
    {'foo_argument_opt'      }     10        0.077103
    {'foo_nargin'            }     15       0.0013069
    {'foo_exist'             }     15        0.083586
    {'foo_inputparser'       }     15         0.60135
    {'foo_inputparser_struct'}     15         0.25337
    {'foo_argument'          }     15       0.0013697
    {'foo_argument_opt'      }     15        0.095364

相关问题