【问题标题】:time needed to access struct vs. "loose" variable访问结构与“松散”变量所需的时间
【发布时间】:2017-04-18 08:25:51
【问题描述】:

我对从 matlab 结构或 matlab 变量(任何数组)访问/重新分配变量时的时间有疑问:

想象一下,您有一个创建十个变量(不同维度和大小的数组)的函数。该函数在另一个需要生成这些变量的函数中被调用。

现在,因为从函数中获取十个变量看起来很麻烦,所以我考虑将这十个变量存储在一个结构中,并更改我的初始函数,使其仅输出一个结构(有十个字段)而不是十个变量。

因为时间对我来说至关重要(它是脑电图实验的代码),所以我想确保 struct 方法不慢,所以我编写了以下测试函数。

function test_timingStructs

%% define struct
strct.a=1; strct.b=2; strct.c=3;

%% define "loose" variables
a = 1; b = 2; c = 3;

%% How many runs?
runs = 1000;

%% time access to struct
x = []; % empty variable
tic
for i=1:runs
    x = strct.a; x = strct.b; x = strct.c;
end
t_struct = toc;

%% time access to "loose variables"
x = []; % empty variable
tic
for i=1:runs
    x = a; x = b; x = c;
end
t_loose = toc;

%% Plot results
close all; figure;
bar(cat(2,t_struct,t_loose));
set(gca,'xticklabel', {'struct', 'loose variable'})
xlabel('variable type accessed', 'fontsize', 12)
ylabel(sprintf('time (ms) needed for %d accesses to 3 different variables', runs), 'fontsize', 12)
title('Access timing: struct vs "loose" variables', 'fontsize', 15)

end

根据结果,访问结构以获取字段的值比仅访问变量要慢得多。我可以根据我所做的测试做出这个假设吗?

当我想访问它们时,是否有另一种方法可以整齐地“打包”十个变量而不会浪费时间?

【问题讨论】:

  • 虽然由于需要额外的subsrefstruct 引用相对于变量可能会更慢,但每次迭代的最大绝对时间约为 1 微秒(在我六岁的孩子身上)安装 R2016a 的机器)。在不了解您的需求的情况下,我认为这无关紧要,但如果没有完整的测试用例,不确定性是非零的。
  • tictoc 的单次迭代不是一个好的基准测试方法。使用多次运行并平均结果或使用timeit。这也很大程度上取决于 MATLAB 版本和硬件。顺便说一句,如果微秒级的时间真的不够,那么我会推荐一种不同的语言。

标签: matlab variables variable-assignment timing matlab-struct


【解决方案1】:

理论上,是的,访问struct 中的数据将比访问存储在变量中的数据慢。这只是更高级别数据类型产生的开销。

但是

在您的测试中,您只测量两种数据结构中数据的访问时间。当您使用变量时,只需将一个变量分配给另一个变量需要很少的时间,因为 MATLAB 使用写时复制,并且实际上不会在内存中复制数据直到它被修改。 p>

因此,您编写的测试对于确定使用 struct 的实际成本不是很有用,因为我确信您的函数对它的数据做了一些事情收到。一旦您修改数据,MATLAB 将复制数据并执行请求的操作。因此,要确定 struct 的性能损失是多少,您应该对实际函数而不是您正在使用的无操作函数计时。

更真实的测试

我在下面编写了一个测试,比较了struct 和被调用函数修改数据和不修改数据的变量访问。

function timeaccess

    sz = round(linspace(1, 200, 100));

    [times1, times2, times3, times4] = deal(zeros(size(sz)));

    for k = 1:numel(sz)

        n = sz(k);

        S = struct('a', rand(n), 'b', rand(n), 'c', rand(n));
        times1(k) = timeit(@()access_struct(S));
        S = struct('a', rand(n), 'b', rand(n), 'c', rand(n));
        times2(k) = timeit(@()access_struct2(S));
        a = rand(n); b = rand(n); c = rand(n);
        times3(k) = timeit(@()access_vars(a, b, c));
        a = rand(n); b = rand(n); c = rand(n);
        times4(k) = timeit(@()access_vars2(a, b, c));
    end

    figure

    hax1 = subplot(1,2,1);
    ylabel('Execution Time (ms)')
    xlabel('Size of Variables');

    hold on

    plot(sz, times2 * 1000, 'DisplayName', 'Struct w/o modification')
    plot(sz, times4 * 1000, 'DisplayName', 'Variables w/o modification')

    legend(findall(hax1, 'type', 'line'))

    hax2 = subplot(1,2,2);
    ylabel('Execution Time (ms)')
    xlabel('Size of Variables');
    hold on

    plot(sz, times1 * 1000, 'DisplayName', 'Struct w modification')
    plot(sz, times3 * 1000, 'DisplayName', 'Variables w modification')

    legend(findall(hax2, 'type', 'line'))

    saveas(gcf, 'data_manipulation.png')
    legend()
end

function [a, b, c] = access_struct(S)
    a = S.a + 1;
    b = S.b + 2;
    c = S.c + 3;
end

function [a, b, c] = access_struct2(S)
    a = S.a;
    b = S.b;
    c = S.c;
end

function [d, e, f] = access_vars(a, b, c)
    d = a + 1;
    e = b + 1;
    f = c + 1;
end

function [d, e, f] = access_vars2(a, b, c)
    d = a;
    e = b;
    f = c;
end

结果

如您所见,struct 只是将一个变量分配给另一个变量的速度较慢,但​​只要我执行一个操作(这里我有一个非常简单的操作,即为每个变量添加一个常量),效果的访问时间可以忽略不计。

总结

根据上面的测试,我假设两者之间的时间差对于您的用例来说可以忽略不计。即使struct 有点慢,它也可能是一个更简洁的设计,并产生更易读/​​可维护的代码,并且可能值得在性能上有所不同。

如果您非常关心性能,可能值得研究 C/C++ mex 函数来为您完成一些繁重的工作或切换到比 MATLAB 性能更高的语言。

【讨论】:

    猜你喜欢
    • 2013-08-02
    • 2018-04-27
    • 2010-11-25
    • 2013-11-02
    • 2018-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    相关资源
    最近更新 更多