【问题标题】:Performance of `eval` compared to `str2func` to evalulate a function from a string`eval` 与 `str2func` 相比的性能,可从字符串评估函数
【发布时间】:2017-09-14 21:59:22
【问题描述】:

eval 和 str2func 都能够计算由字符串 f.e. 表示的函数。 f='a^x+exp(b)+sin(c*x)+d':

  • 使用eval:

    y = eval(f)
    

    或(由rahnema1建议)

    fHandle = eval(['@(x, a, b, c, d) ' f]);
    y = fHandle(x, a, b, c, d);
    
  • 使用str2func:

    fHandle = str2func(['@(x, a, b, c, d) ' f]);
    y = fHandle(x, a, b, c, d);
    

这两种方法中哪一种性能最好?

备注

请注意,此基准测试的灵感来自 this question。

请注意,我知道使用eval 和str2func 通常是不好的做法[1][2](如 cmets 中所述)。

【问题讨论】:

  • 好主意,但请在您的回答中提及eval 对于reasons 而言是不可取的比性能更基本
  • 除了性能之外,eval 与str2func 相比在哪些方面不受欢迎?
  • @m7913d 在我对the question which inspired your benchmark 的回答中,我链接到documentation on why eval is undesirable。也就是说,它很难调试,它可能会意外地覆盖工作区数据,它不会为将来的运行而编译(这是性能方面),并且通过连接创建的字符串作为eval 的输入可能难以阅读。通常可以避免,所以应该是
  • @Wolfie 我认为这些论点在某种程度上也适用于str2func,尤其是最后两项。
  • 我询问了new question,因为我不确定哪些根本原因仅适用于eval 而不适用于str2func。

标签: matlab performance eval


【解决方案1】:

简答:使用str2func。

基准测试

基准测试将针对N 的不同x 值评估函数。

f='a^x+exp(b)+sin(c*x)+d';

Ns = linspace(1, 1000, 20);
timeEval = zeros(size(Ns));
timeEvalHandle = zeros(size(Ns));
timeStr2func = zeros(size(Ns));
for i=1:length(Ns)
  N = Ns(i);
  timeEval(i) = timeit(@() useEval(f, N));
  timeEvalHandle(i) = timeit(@() useEvalHandle(f, N));
  timeStr2func(i) = timeit(@() useStr2func(f, N));
end

figure
plot(Ns, timeEval, 'DisplayName', 'time eval');
hold on
plot(Ns, timeEvalHandle, 'DisplayName', 'time eval');
hold on
plot(Ns, timeStr2func, 'DisplayName', 'time str2func');
legend show
xlabel('N');

figure
plot(Ns, timeEval./timeStr2func, 'DisplayName', 'time_{eval}/time_{str2func}');
hold on
plot(Ns, timeEvalHandle./timeStr2func, 'DisplayName', 'time_{eval handle}/time_{str2func}');
legend show
xlabel('N');

figure
plot(Ns, timeEvalHandle./timeStr2func);
ylabel('time_{eval handle}/time_{str2func}')
xlabel('N');

function y = useEval(f, N)
  a = 1; b = 2; c = 3; d = 4;
  for x=1:N
    y = eval(f);
  end
end

function y = useEvalHandle(f, N)
  a = 1; b = 2; c = 3; d = 4;
  fHandle = eval(['@(x, a, b, c, d) ' f]);
  for x=1:N
    y = fHandle(x, a, b, c, d);
  end
end

function y = useStr2func(f, N)
  a = 1; b = 2; c = 3; d = 4;
  fHandle = str2func(['@(x, a, b, c, d) ' f]);
  for x=1:N
    y = fHandle(x, a, b, c, d);
  end
end

str2func vs eval(无函数句柄): 结果表明,即使对函数进行一次评估,使用str2func 也比使用eval 快50% 左右(没有函数句柄)。对于大量评估,str2func 可能快 100 倍左右(取决于您正在评估的函数)。

str2func 与 eval(带有函数句柄): 对于单次评估,eval 比 str2func 慢大约 100%,但对于大量计算,变得几乎同样快评估次数(eval 慢了约 5%)。

eval 带和不带函数句柄:请注意,对于单个评估,使用 eval 创建函数句柄比直接评估要慢约 50%。

结论:str2func总是比eval快。

【讨论】:

    【解决方案2】:

    在以下基准测试中,创建了一组函数句柄,并将eval 的性能与str2func 的性能进行比较,以评估字符串。函数是带有 +- 号的变量的组合。

    n = 16;
    op=char((dec2bin(0:2^n-1)-48)*2+43);
    vars= 'a':'z';
    v = vars(1:n+1);
    s(1:2^n,1:2:2*n+1)=repmat(v,2^n,1);
    s(:,2:2:end)=op;
    
    h=repmat(['@(' sprintf('%c,',v(1:end-1)) v(end) ')'],2^n,1);
    farray=[h,s];
    tic
    for k = 1:2^n
        f = eval(farray(k,:));
    end
    toc
    
    tic
    for k = 1:2^n
        f = str2func(farray(k,:));
    end
    toc
    

    八度音阶结果:

    两种方法没有区别。

    【讨论】:

    • Matlab 结果:Elapsed time is 62.920203 seconds. Elapsed time is 60.706978 seconds.
    猜你喜欢
    • 2018-02-23
    • 2012-01-04
    • 1970-01-01
    • 2013-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多