MATLAB性能基准测试

17

准备工作:

本文章的主要内容是测试以下问题的解决性能:

给定一个由下划线分隔的数字格式化字符串数组S,例如:

        list_of_words = repmat({'02_04_04_52_23_14_54_672_0'},10,1);

保证所有字符串都满足以下条件:

  1. 只包含十进制数字和下划线;
  2. 下划线的数量相同;
  3. 没有连续的下划线。

编写MATLAB代码将字符串的单元格数组转换为双精度的S×M数值矩阵(值小1000倍) ,其中S是字符串的数量,M是字符串中数字的数量。

在StackOverflow上发布了一个非常类似的问题,并提出了几个解决方案。最初的目标是提高速度性能。

代码:

其中两种以速度为设计目标的解决方案在不同的MATLAB安装之间甚至在不同的运行之间表现差异很大。此外,它们的实现方式也截然不同。

在黑暗角落里,你会发现一个与MATLAB最神圣的原则相悖的解决方案:eval是邪恶的,应尽可能避免循环。但是,该代码试图通过避免重复的内存分配、使用将字符串快速转换为数字的方法和执行原地操作来优化速度:

%'eval_and_loops_solution.m'
function array_of_numbers = eval_and_loops_solution(list_of_words)

        n_numbers = 1 + sum(list_of_words{1}=='_');
        n_words   = numel(list_of_words);

        array_of_numbers = zeros(n_numbers, n_words);

        for k = 1:n_words
                temp = ['[', list_of_words{k}, ']'];
                temp(temp=='_') = ';';
                array_of_numbers(:,k) = eval(temp);
        end;

         %'this is a waste of memory, but is kind of required'
        array_of_numbers = transpose(array_of_numbers / 1000);

end

注意:原始解决方案将结果作为M×Sdouble数组返回。 该代码已适用于S×M;但是,此适配器会使用两倍的内存。 是的,我编写了这个解决方案。

在明显的角落,您将找到一个真正符合MATLAB精神的解决方案,它避免使用循环和eval,而是喜欢单个sscanf读取所有字符串(这是一种巧妙的方法,避免了调用函数S次数的开销):

%'single_sscanf_solution.m'
function array_of_numbers = single_sscanf_solution(list_of_words)

        N = 1 + sum(list_of_words{1}=='_'); %'hard-coded in the original'
        lens = cellfun(@numel,list_of_words);
        tlens = sum(lens);
        idx(1,tlens)=0;
        idx(cumsum(lens(1:end-1))+1)=1;
        idx2 = (1:tlens) + cumsum(idx);

        one_str(1:max(idx2)+1)='_';
        one_str(idx2) = [list_of_words{:}];
        delim = repmat('%d_',1,N*numel(lens));
        array_of_numbers = reshape(sscanf(one_str, delim),N,[])'./1000;

end

注意:此解决方案属于@Divakar

裁判员由两个函数组成:一个生成测试用例,另一个进行时间测量。

测试用例生成器将10个介于1和9999之间的随机整数分组到一个单元数组的下划线分隔字符串中(为了简单起见);但是,实现应仅假定数字为正或零,并且数字应适合double

%'referee_test_case.m'
function list_of_words = referee_test_case(n_words)

        NUM_PER_WORD  = 10;
        NUM_MAX       = 9999;

        word_format   = [repmat('%d_', 1, NUM_PER_WORD-1), '%d'];
        list_of_words = cell(n_words,1);

        fprintf('Generating %d-words test case...\n', n_words);
        for k = 1:n_words
                list_of_words{k} = sprintf(word_format, randi(NUM_MAX, [1, NUM_PER_WORD]));
        end;

end

定时函数需要一个测试用例和任意数量的处理函数句柄作为参数;它的实现方式是如果一个函数出错不应影响其他函数的执行。它使用了 @Divakar 和 @LuisMendo 推荐的 timeit 函数;对于那些在默认的 MATLAB 安装中没有这个函数的用户,可以从 MATLAB Central / 文件交换中心下载:

%'referee_timing.m'
function referee_timing(test_case, varargin)
        %' Specify the test case as a cell array of strings, then the function '
        %' handles that will process the test case.                            '
        %'                                                                     '
        %' The function uses timeit() to evaluate the performance of different '
        %' processing handles; if your MATLAB installation does not have it    '
        %' natively, download the available version from File Exchange:        '
        %'                                                                     '
        %'     http://www.mathworks.com/matlabcentral/fileexchange/18798-timeit-benchmarking-function '

        fprintf('Timing %d-words test case...\n', numel(test_case));
        for k = 1:numel(varargin)
                try
                        t = timeit(@() varargin{k}(test_case));
                        fprintf('  %s: %f[s]\n', func2str(varargin{k}), t);
                catch ME
                        fprintf('  %s: Error - %s\n', func2str(varargin{k}), ME.message);
                end;
        end;
end

问题:

如前所述,从一个MATLAB安装到另一个MATLAB安装,甚至从一次运行到另一次运行,结果似乎存在差异。我提出的问题有三个方面:

  1. 在您特定的MATLAB安装(版本+操作系统+硬件)中,这两种解决方案相对于彼此的表现如何?
  2. 是否可能以可观的方式改进一种或另一种解决方案?
  3. 是否存在基于完全不同想法/函数的更快速的MATLAB本地解决方案(例如,无MEX或特殊工具箱)?

对于第1个问题(基准测试),请在MATLAB路径中创建四个函数文件eval_and_loops_solution.msingle_sscanf_solution.mreferee_test_case.mreferee_timig.m以及您希望测试的其他函数(例如,答案中提出的实现)。使用它们来进行多个单词数的测试,例如使用以下脚本:

%'test.m'
clc;
feature accel on;  %'tune for speed'

%'low memory stress'
referee_timing( ...
   referee_test_case(10^4), ...
   @eval_and_loops_solution, ...
   @single_sscanf_solution ... %'add here other functions'
);

%'medium memory stress'
referee_timing( ...
   referee_test_case(10^5), ...
   @eval_and_loops_solution, ...
   @single_sscanf_solution ... %'add here other functions'
);

%'high memory stress'
referee_timing( ...
   referee_test_case(10^6), ...
   @eval_and_loops_solution, ...
   @single_sscanf_solution ... %'add here other functions'
);

发布结果时,请注明您的MATLAB版本、操作系统、RAM大小和CPU型号。请注意,对于大量单词,这些测试可能需要一些时间!但是,运行此脚本不会更改当前工作区的内容。
对于第2或第3点,您可以发布使用与eval_and_loops_solution.msingle_sscanf_solution.m相同的输入/输出约定的代码,以及支持该声明的基准测试。
赏金:
我将为每个基准测试答案投票,并鼓励所有人这样做。这是每个人为贡献其技能、时间和处理能力所能做的最少的事情。
+500赏金将被授予最快代码的作者,无论是两个提议中的一个还是超越它们的第三个新代码。我真的希望这能符合普遍的协议。奖金将在发布原始日期后的一周内发放。

3
哈哈,你真不放弃啊! :) - Divakar
1
@Divakar 哈哈,不是的。 :-) 我还是很好奇。我希望这篇文章的语气现在更加恰当了。 - user2271770
1
另外,你确定在函数内使用tic/toc是个好主意吗?也许应该使用timeit代替? - Divakar
+1,我喜欢这个。如果你被聘请来优化这样的脚本,那么你就是一个狡猾的家伙 =P - Stewie Griffin
@RobertP。哈哈,不,我没有被付款,这只是出于好奇心。还有一点点自豪感。 :-) - user2271770
显示剩余20条评论
9个回答

7

这里有一些纯MATLAB实现供您进行基准测试。其中一些借鉴了其他解决方案的想法。

function M = func_eval_strjoin(C)
    M = eval(['[' strjoin(strrep(C,'_',' ').',';') ']']);
end

function M = func_eval_sprintf(C)
    C = strrep(C,'_',' ');
    M = eval(['[' sprintf('%s;',C{:}) ']']);
end

function M = func_eval_cellfun(C)
    M = cell2mat(cellfun(@eval, strcat('[',strrep(C,'_',' '),']'), 'Uniform',false));
end

function M = func_eval_loop(C)
    M = zeros(numel(C),nnz(C{1}=='_')+1);
    for i=1:numel(C)
        M(i,:) = eval(['[' strrep(C{i},'_',' ') ']']);
    end
end

function M = func_str2num_strjoin(C)
    M = reshape(str2num(strjoin(strrep(C.','_',' '))), [], numel(C)).';
end

function M = func_str2num_sprintf(C)
    C = strrep(C,'_',' ');
    M = reshape(str2num(sprintf('%s ',C{:})), [], numel(C)).';
end

function M = func_str2num_cellfun(C)
    M = cell2mat(cellfun(@str2num, strrep(C, '_', ' '), 'Uniform',false));
end

function M = func_str2num_loop(C)
    M = zeros(numel(C),nnz(C{1}=='_')+1);
    for i=1:numel(C)
        M(i,:) = str2num(strrep(C{i}, '_', ' '));
    end
end

function M = func_sscanf_strjoin(C)
    M = reshape(sscanf(strjoin(C', '_'), '%f_'), [], numel(C)).';
end

function M = func_sscanf_sprintf(C)
    M = reshape(sscanf(sprintf('%s_',C{:}),'%f_'), [], numel(C)).';
end

function M = func_sscanf_cellfun(C)
    M = cell2mat(cellfun(@(c) sscanf(c, '%f_'), C, 'Uniform',false).').';
end

function M = func_sscanf_loop(C)
    M = zeros(numel(C),nnz(C{1}=='_')+1);
    for i=1:numel(C)
        M(i,:) = sscanf(C{i}, '%f_');
    end
end

function M = func_textscan_strjoin(C)
    M = textscan(strjoin(C', '_'), '%.0f', 'Delimiter','_');
    M = reshape(M{1}, [], numel(C)).';
end

function M = func_textscan_sprintf(C)
    M = textscan(sprintf('%s_',C{:}),'%.0f', 'Delimiter','_');
    M = reshape(M{1}, [], numel(C)).';
end

function M = func_textscan_cellfun(C)
    M = cell2mat(cellfun(@(str) textscan(str, '%.0f', 'Delimiter','_'), C).').';
end

function M = func_textscan_loop(C)
    M = zeros(numel(C),nnz(C{1}=='_')+1);
    for i=1:numel(C)
        x = textscan(C{i}, '%.0f', 'Delimiter','_');
        M(i,:) = x{1};
    end
end

function M = func_str2double_strsplit_strjoin(C)
    M = reshape(str2double(strsplit(strjoin(C','_'),'_')), [], numel(C)).';
end

function M = func_str2double_strsplit_sprintf(C)
    M = strsplit(sprintf('%s_',C{:}), '_');
    M = reshape(str2double(M(1:end-1)), [], numel(C)).';
end

function M = func_str2double_strsplit(C)
    M = cellfun(@(c) strsplit(c,'_'), C, 'Uniform',false);
    M = str2double(cat(1,M{:}));
end

function M = func_str2double_strsplit_cellfun(C)
    M = cell2mat(cellfun(@(c) str2double(strsplit(c,'_')), C, 'Uniform',false));
end

function M = func_str2double_strsplit_loop(C)
    M = zeros(numel(C),nnz(C{1}=='_')+1);
    for i=1:numel(C)
        M(i,:) = str2double(strsplit(C{i},'_'));
    end
end

function M = func_str2double_regex_split_strjoin(C)
    M = reshape(str2double(regexp(strjoin(C.','_'), '_', 'split')), [], numel(C)).';
end

function M = func_str2double_regex_split_sprintf(C)
    M = regexp(sprintf('%s_',C{:}), '_', 'split');
    M = reshape(str2double(M(1:end-1)), [], numel(C)).';
end

function M = func_str2double_regex_split(C)
    M = regexp(C, '_', 'split');
    M = reshape(str2double([M{:}]), [], numel(C)).';
end

function M = func_str2double_regex_split_cellfun(C)
    M = cell2mat(cellfun(@str2double, regexp(C, '_', 'split'), 'Uniform',false));
end

function M = func_str2double_regex_split_loop(C)
    M = zeros(numel(C),nnz(C{1}=='_')+1);
    for i=1:numel(C)
        M(i,:) = str2double(regexp(C{i}, '_', 'split'));
    end
end

function M = func_str2double_regex_tokens_strjoin_1(C)
    M = reshape(cellfun(@str2double, regexp(strjoin(C.','_'), '(\d+)', 'tokens')), [], numel(C)).';
end

function M = func_str2double_regex_tokens_strjoin_2(C)
    M = regexp(strjoin(C.','_'), '(\d+)', 'tokens');
    M = reshape(str2double([M{:}]), [], numel(C)).';
end

function M = func_str2double_regex_tokens_sprintf_1(C)
    M = reshape(cellfun(@str2double, regexp(sprintf('%s_',C{:}), '(\d+)', 'tokens')), [], numel(C)).';
end

function M = func_str2double_regex_tokens_sprintf_2(C)
    M = regexp(sprintf('%s_',C{:}), '(\d+)', 'tokens');
    M = reshape(str2double([M{:}]), [], numel(C)).';
end

function M = func_str2double_regex_tokens(C)
    M = regexp(C, '(\d+)', 'tokens');
    M = cat(1,M{:});
    M = reshape(str2double([M{:}]), size(M));
end

function M = func_str2double_regex_tokens_cellfun(C)
    M = regexp(C, '(\d+)', 'tokens');
    M = cellfun(@str2double, cat(1,M{:}));
end

function M = func_str2double_regex_tokens_loop(C)
    M = zeros(numel(C),nnz(C{1}=='_')+1);
    for i=1:numel(C)
        x = regexp(C{i}, '(\d+)', 'tokens');
        M(i,:) = str2double([x{:}]);
    end
end

大多数方法都是同一思路的变体,只是实现方式略有不同(例如:使用显式for循环与cellfun、使用strjoinsprintf将字符串单元数组连接成一个字符串等)。
让我更详细地解释一下:
  • 有基于eval的解决方案。我们可以在循环中应用eval,也可以在将字符串展平后进行一次调用。

  • 类似地,还有基于调用str2num(在将下划线替换为空格后)的解决方案。值得注意的是,str2num 本身在内部调用了eval

  • 还有基于sscanftextscan的解决方案。与之前类似,我们可以在循环中使用它们,或者在一个长字符串上调用它们。

  • 另一组解决方案是基于通过下划线分隔符拆分字符串后调用str2double。同样,有其他拆分字符串的方法(使用带有“split”选项的regex,或使用strsplit函数)。

  • 最后,还有一组基于正则表达式匹配的解决方案。


编辑:

我创建了一组用于基准测试各种实现的函数(GitHub Gist)。这里是到目前为止发布的所有解决方案的预打包文件。我包含了编译的MEX函数(64位Windows),以及MinGW-w64 DLL依赖项。

这是在我的机器上运行的结果(装有四核Intel Core i7 CPU、8GB内存、Win8.1和MATLAB R2014a的笔记本电脑)。我测试了以下大小:10x10、100x10、1000x10和10000x10。正如你所看到的,随着数据大小的增加,MEX解决方案表现更好...


编辑#2:

根据要求,我使用@chappjc修改后的MEX文件和@Divakar的GPU版本更新了我的测试结果。这里是文件的更新归档

我使用与之前相同的机器,并将单元数组大小增加到1e5。我的GPU设备对于笔记本电脑来说还不错:

>> gpuDevice
ans = 
  CUDADevice with properties:

                      Name: 'GeForce GT 630M'
                     Index: 1
         ComputeCapability: '2.1'
            SupportsDouble: 1
             DriverVersion: 5.5000
            ToolkitVersion: 5.5000
        MaxThreadsPerBlock: 1024
          MaxShmemPerBlock: 49152
        MaxThreadBlockSize: [1024 1024 64]
               MaxGridSize: [65535 65535 65535]
                 SIMDWidth: 32
               TotalMemory: 2.1475e+09
                FreeMemory: 2.0453e+09
       MultiprocessorCount: 2
              ClockRateKHz: 950000
               ComputeMode: 'Default'
      GPUOverlapsTransfers: 1
    KernelExecutionTimeout: 1
          CanMapHostMemory: 1
           DeviceSupported: 1
            DeviceSelected: 1

这里是最新的结果:

fig1 fig2

>> t
t = 
                      func                      nrows    ncols       time   
    ________________________________________    _____    _____    __________
    'func_eval_cellfun'                            10    10       0.00044645
    'func_eval_loop'                               10    10        0.0001554
    'func_eval_sprintf'                            10    10       7.6547e-05
    'func_eval_strjoin'                            10    10       0.00056739
    'func_sscanf_cellfun'                          10    10       0.00037247
    'func_sscanf_loop'                             10    10       0.00017182
    'func_sscanf_sprintf'                          10    10       8.4928e-05
    'func_sscanf_strjoin'                          10    10       0.00056388
    'func_str2num_cellfun'                         10    10       0.00039231
    'func_str2num_loop'                            10    10       0.00033852
    'func_str2num_sprintf'                         10    10       0.00010862
    'func_str2num_strjoin'                         10    10       0.00057953
    'func_textscan_cellfun'                        10    10       0.00044585
    'func_textscan_loop'                           10    10       0.00024666
    'func_textscan_sprintf'                        10    10       9.4507e-05
    'func_textscan_strjoin'                        10    10       0.00056123
    'solution_bsxfun_bytestream_Divakar'           10    10       0.00018166
    'solution_bsxfun_bytestream_gpu_Divakar'       10    10        0.0029487
    'solution_bsxfun_cumsum_Divakar'               10    10       0.00016396
    'solution_bsxfun_sprintf_Divakar'              10    10       0.00012932
    'solution_bsxfun_sprintf_gpu_Divakar'          10    10         0.002315
    'solution_eval_loops_CSTLink'                  10    10       0.00017191
    'solution_loops_CSTLink'                       10    10       6.5514e-05
    'solution_mex_Amro'                            10    10       6.4487e-05
    'solution_mex_chappjc'                         10    10       4.2507e-05
    'solution_mex_omp_Amro'                        10    10       0.00027411
    'solution_mex_omp_chappjc'                     10    10       0.00013017
    'solution_sscanf_Divakar'                      10    10       0.00020458
    'solution_sscanf_char_LuisMendo'               10    10       0.00011144
    'solution_textscan_sprintf_chappjc'            10    10       0.00010528
    'func_eval_cellfun'                           100    10        0.0011801
    'func_eval_loop'                              100    10         0.001059
    'func_eval_sprintf'                           100    10       0.00025547
    'func_eval_strjoin'                           100    10        0.0011824
    'func_sscanf_cellfun'                         100    10        0.0023356
    'func_sscanf_loop'                            100    10        0.0012338
    'func_sscanf_sprintf'                         100    10       0.00031012
    'func_sscanf_strjoin'                         100    10        0.0011334
    'func_str2num_cellfun'                        100    10         0.002635
    'func_str2num_loop'                           100    10        0.0028056
    'func_str2num_sprintf'                        100    10       0.00027899
    'func_str2num_strjoin'                        100    10        0.0012117
    'func_textscan_cellfun'                       100    10        0.0029546
    'func_textscan_loop'                          100    10        0.0018652
    'func_textscan_sprintf'                       100    10       0.00028506
    'func_textscan_strjoin'                       100    10         0.001125
    'solution_bsxfun_bytestream_Divakar'          100    10       0.00040027
    'solution_bsxfun_bytestream_gpu_Divakar'      100    10        0.0032536
    'solution_bsxfun_cumsum_Divakar'              100    10       0.00041019
    'solution_bsxfun_sprintf_Divakar'             100    10       0.00031089
    'solution_bsxfun_sprintf_gpu_Divakar'         100    10        0.0026271
    'solution_eval_loops_CSTLink'                 100    10        0.0012294
    'solution_loops_CSTLink'                      100    10       0.00033501
    'solution_mex_Amro'                           100    10       0.00027069
    'solution_mex_chappjc'                        100    10       0.00010682
    'solution_mex_omp_Amro'                       100    10       0.00039385
    'solution_mex_omp_chappjc'                    100    10       0.00015232
    'solution_sscanf_Divakar'                     100    10        0.0010108
    'solution_sscanf_char_LuisMendo'              100    10       0.00050153
    'solution_textscan_sprintf_chappjc'           100    10       0.00026958
    'func_eval_cellfun'                          1000    10        0.0092491
    'func_eval_loop'                             1000    10         0.016145
    'func_eval_sprintf'                          1000    10         0.067573
    'func_eval_strjoin'                          1000    10         0.070024
    'func_sscanf_cellfun'                        1000    10         0.020954
    'func_sscanf_loop'                           1000    10         0.011224
    'func_sscanf_sprintf'                        1000    10        0.0022546
    'func_sscanf_strjoin'                        1000    10        0.0058568
    'func_str2num_cellfun'                       1000    10         0.024699
    'func_str2num_loop'                          1000    10          0.02645
    'func_str2num_sprintf'                       1000    10          0.05713
    'func_str2num_strjoin'                       1000    10         0.060093
    'func_textscan_cellfun'                      1000    10          0.02592
    'func_textscan_loop'                         1000    10         0.017589
    'func_textscan_sprintf'                      1000    10        0.0020249
    'func_textscan_strjoin'                      1000    10        0.0055364
    'solution_bsxfun_bytestream_Divakar'         1000    10        0.0018817
    'solution_bsxfun_bytestream_gpu_Divakar'     1000    10        0.0066003
    'solution_bsxfun_cumsum_Divakar'             1000    10         0.001982
    'solution_bsxfun_sprintf_Divakar'            1000    10        0.0015578
    'solution_bsxfun_sprintf_gpu_Divakar'        1000    10        0.0046952
    'solution_eval_loops_CSTLink'                1000    10         0.011481
    'solution_loops_CSTLink'                     1000    10        0.0027254
    'solution_mex_Amro'                          1000    10        0.0022698
    'solution_mex_chappjc'                       1000    10        0.0006967
    'solution_mex_omp_Amro'                      1000    10        0.0015025
    'solution_mex_omp_chappjc'                   1000    10       0.00041463
    'solution_sscanf_Divakar'                    1000    10        0.0093785
    'solution_sscanf_char_LuisMendo'             1000    10        0.0038031
    'solution_textscan_sprintf_chappjc'          1000    10        0.0020323
    'func_eval_cellfun'                         10000    10         0.083676
    'func_eval_loop'                            10000    10         0.098798
    'func_eval_sprintf'                         10000    10          0.60429
    'func_eval_strjoin'                         10000    10          0.63656
    'func_sscanf_cellfun'                       10000    10          0.20675
    'func_sscanf_loop'                          10000    10           0.1088
    'func_sscanf_sprintf'                       10000    10         0.021725
    'func_sscanf_strjoin'                       10000    10         0.052341
    'func_str2num_cellfun'                      10000    10          0.24192
    'func_str2num_loop'                         10000    10          0.26538
    'func_str2num_sprintf'                      10000    10          0.53451
    'func_str2num_strjoin'                      10000    10          0.56759
    'func_textscan_cellfun'                     10000    10          0.25474
    'func_textscan_loop'                        10000    10          0.17402
    'func_textscan_sprintf'                     10000    10         0.018799
    'func_textscan_strjoin'                     10000    10          0.04965
    'solution_bsxfun_bytestream_Divakar'        10000    10         0.019165
    'solution_bsxfun_bytestream_gpu_Divakar'    10000    10         0.031283
    'solution_bsxfun_cumsum_Divakar'            10000    10         0.027986
    'solution_bsxfun_sprintf_Divakar'           10000    10         0.017761
    'solution_bsxfun_sprintf_gpu_Divakar'       10000    10         0.024821
    'solution_eval_loops_CSTLink'               10000    10          0.10885
    'solution_loops_CSTLink'                    10000    10         0.025136
    'solution_mex_Amro'                         10000    10         0.021374
    'solution_mex_chappjc'                      10000    10        0.0060774
    'solution_mex_omp_Amro'                     10000    10        0.0076461
    'solution_mex_omp_chappjc'                  10000    10         0.002058
    'solution_sscanf_Divakar'                   10000    10          0.10503
    'solution_sscanf_char_LuisMendo'            10000    10         0.035483
    'solution_textscan_sprintf_chappjc'         10000    10         0.018772
    'func_eval_cellfun'                         1e+05    10          0.85115
    'func_eval_loop'                            1e+05    10          0.97977
    'func_eval_sprintf'                         1e+05    10           6.2422
    'func_eval_strjoin'                         1e+05    10           6.5012
    'func_sscanf_cellfun'                       1e+05    10           2.0761
    'func_sscanf_loop'                          1e+05    10           1.0865
    'func_sscanf_sprintf'                       1e+05    10          0.22618
    'func_sscanf_strjoin'                       1e+05    10          0.53146
    'func_str2num_cellfun'                      1e+05    10           2.4041
    'func_str2num_loop'                         1e+05    10           2.6431
    'func_str2num_sprintf'                      1e+05    10              5.4
    'func_str2num_strjoin'                      1e+05    10           5.6967
    'func_textscan_cellfun'                     1e+05    10           2.5696
    'func_textscan_loop'                        1e+05    10           1.7175
    'func_textscan_sprintf'                     1e+05    10          0.19759
    'func_textscan_strjoin'                     1e+05    10          0.50314
    'solution_bsxfun_bytestream_Divakar'        1e+05    10          0.21884
    'solution_bsxfun_bytestream_gpu_Divakar'    1e+05    10          0.23607
    'solution_bsxfun_cumsum_Divakar'            1e+05    10          0.29511
    'solution_bsxfun_sprintf_Divakar'           1e+05    10          0.19882
    'solution_bsxfun_sprintf_gpu_Divakar'       1e+05    10          0.17923
    'solution_eval_loops_CSTLink'               1e+05    10           1.0943
    'solution_loops_CSTLink'                    1e+05    10           0.2534
    'solution_mex_Amro'                         1e+05    10          0.21575
    'solution_mex_chappjc'                      1e+05    10         0.060666
    'solution_mex_omp_Amro'                     1e+05    10         0.072168
    'solution_mex_omp_chappjc'                  1e+05    10         0.024385
    'solution_sscanf_Divakar'                   1e+05    10           1.0992
    'solution_sscanf_char_LuisMendo'            1e+05    10          0.36688
    'solution_textscan_sprintf_chappjc'         1e+05    10          0.19755

2
哈哈,我明白了,你好像不太感兴趣基准测试... :-) 好的:1) regexp 是慢的,2) str2num 其实是一个包装器中的 eval,3) sscanftextscan 在我看来其实很快,但是调用它们多次时有开销;作为交换,必须针对大输入字符串构建大格式字符串。4) str2double 可能很有趣,我没有尝试过。希望这不是对发布的 DOS 攻击。 :-) - user2271770
@CST-Link,“str2double”可能是最糟糕的选择。这是我第一次尝试,速度非常慢。 - chappjc
@CST-Link:我并不声称它们都很快(事实上,regexp和str2double非常慢!)。sscanf和textscan确实是最快的,其次是基于eval的方法(在一定程度上)。我的观点只是展示各种方法,这似乎是你正在寻找的...如果你想要性能,那就走C/C++之路吧 :) - Amro
@chappjc: 我也是,我没有看到设置“delimiter”或不设置的区别。 - Amro
解压后的基准测试文件 ZIP 给出了“输入类型为'cell'的参数的未定义函数'func_eval_cellfun'。” :( - Ben Voigt
显示剩余13条评论

6

这是在Amro的MEX解决方案基础上构建的。由于CST-Link所定义的问题非常严格,因此可以通过牺牲健壮性和放弃错误处理来实现快速实现。因此,请按照规定的格式格式化输入!

使用以下内容替换Amro源代码中的主循环,即可在不使用多线程的情况下将速度提高约4倍(完整源代码):

// extract numbers from strings
for (mwIndex idx=0, i=0; idx<n_words; ++idx) {
    std::string str = getString(cellstr, idx);

    std::string::const_iterator istr = str.cbegin();
    for (; istr != str.cend(); ++istr) {
        if (*istr < '0' || *istr > '9')
        {
            ++i;
            continue;
        }
            out[i] *= 10;
            out[i] += *istr - '0';
    }
    ++i;
}

更多手动优化可以完成,但我要睡觉了。此外,我计划在某个时候制作多线程版本,但添加#pragma非常简单。
基准测试(更新倒计时12小时的宽限期) 使用Amro最新函数包加上Ben Voigt的解决方案进行的基准测试在不同的机器上显示出不同的时间,但值得一提的是几种解决方案之间存在着虚拟平局。在我的i7笔记本电脑上,使用R2014a 64位Windows 8(在CUDA上),我的textscan、Divakar的最新版本和Ben Voigt的解决方案表现最佳,性能差异无法区分。CST-Link的“all loops”非常接近,但始终比其他方法稍慢一些。这些基准测试使用了高达1e6个字符串。单元数组的大小决定最快的方法。 去掉MEX解决方案(以及GPU,因为我的笔记本电脑),对于不同数量的行,解决方案按以下顺序排列。同样,结果表明适当的方法取决于行数:

i7 16GB R2014a

              解决方案                  1e6     5e5     1e5     1e4     1e3     100
____________________________________    ____    ____    ____    ____    ____    ____
'solution_textscan_sprintf_chappjc' 1 2 2 5 5 4 'solution_bsxfun_sprintf_Divakar' 2 1 3 2 1 8 'func_voigt_loop' 3 3 5 1 2 1 'func_textscan_sprintf' 4 4 4 4 6 3 'solution_bsxfun_bytestream_Divakar' 5 5 6 3 3 10 'solution_loops_CSTLink' 6 7 7 7 8 6 'func_sscanf_sprintf' 7 6 1 6 7 7 'solution_bsxfun_cumsum_Divakar' 8 8 8 8 4 9 'solution_sscanf_char_LuisMendo' 9 9 9 9 9 11 'func_textscan_strjoin' 10 10 15 10 10 16 'func_sscanf_strjoin' 11 11 10 11 11 19 'func_eval_cellfun' 12 12 13 12 12 18 'func_eval_loop' 13 13 11 13 13 12 'solution_eval_loops_CSTLink' 14 15 14 14 14 13 'func_sscanf_loop' 15 14 12 15 15 15 'func_textscan_loop' 16 18 19 18 18 21 'func_sscanf_cellfun' 17 17 16 17 17 22 'func_str2num_cellfun' 18 19 18 19 19 23 'func_str2num_loop' 19 20 20 20 20 24 'solution_sscanf_Divakar' 20 16 17 16 16 20 'func_textscan_cellfun' 21 21 21 21 21 25 'func_str2num_sprintf' 22 23 23 22 22 5 'func_str2num_strjoin' 23 24 25 23 23 17 'func_eval_sprintf' 24 22 24 24 24 2 'func_eval_strjoin' 25 25 22 25 25 14

enter image description here

enter image description here

>> t
t = 
                    func                    nrows    ncols       time   
    ____________________________________    _____    _____    __________

    'func_eval_cellfun'                       100    10       0.00074097
    'func_eval_loop'                          100    10        0.0006137
    'func_eval_sprintf'                       100    10       0.00017814
    'func_eval_strjoin'                       100    10       0.00068062
    'func_sscanf_cellfun'                     100    10        0.0012905
    'func_sscanf_loop'                        100    10       0.00069992
    'func_sscanf_sprintf'                     100    10       0.00022678
    'func_sscanf_strjoin'                     100    10       0.00075428
    'func_str2num_cellfun'                    100    10        0.0014366
    'func_str2num_loop'                       100    10        0.0014904
    'func_str2num_sprintf'                    100    10       0.00020667
    'func_str2num_strjoin'                    100    10       0.00073786
    'func_textscan_cellfun'                   100    10        0.0018517
    'func_textscan_loop'                      100    10        0.0012629
    'func_textscan_sprintf'                   100    10       0.00020092
    'func_textscan_strjoin'                   100    10       0.00071305
    'func_voigt_loop'                         100    10       0.00017711
    'solution_bsxfun_bytestream_Divakar'      100    10       0.00029257
    'solution_bsxfun_cumsum_Divakar'          100    10       0.00028395
    'solution_bsxfun_sprintf_Divakar'         100    10       0.00023879
    'solution_eval_loops_CSTLink'             100    10       0.00066461
    'solution_loops_CSTLink'                  100    10       0.00021923
    'solution_mex_Amro'                       100    10       0.00020502
    'solution_mex_chappjc'                    100    10       6.3164e-05
    'solution_mex_omp_Amro'                   100    10       0.00018224
    'solution_mex_omp_chappjc'                100    10       8.2565e-05
    'solution_sscanf_Divakar'                 100    10       0.00084008
    'solution_sscanf_char_LuisMendo'          100    10       0.00033844
    'solution_textscan_sprintf_chappjc'       100    10       0.00020396
    'func_eval_cellfun'                      1000    10        0.0058036
    'func_eval_loop'                         1000    10        0.0060269
    'func_eval_sprintf'                      1000    10         0.055797
    'func_eval_strjoin'                      1000    10         0.057631
    'func_sscanf_cellfun'                    1000    10         0.011712
    'func_sscanf_loop'                       1000    10        0.0067405
    'func_sscanf_sprintf'                    1000    10        0.0019112
    'func_sscanf_strjoin'                    1000    10        0.0040608
    'func_str2num_cellfun'                   1000    10         0.013712
    'func_str2num_loop'                      1000    10         0.014961
    'func_str2num_sprintf'                   1000    10          0.04916
    'func_str2num_strjoin'                   1000    10         0.051823
    'func_textscan_cellfun'                  1000    10         0.017256
    'func_textscan_loop'                     1000    10         0.012454
    'func_textscan_sprintf'                  1000    10        0.0016489
    'func_textscan_strjoin'                  1000    10        0.0038387
    'func_voigt_loop'                        1000    10        0.0012892
    'solution_bsxfun_bytestream_Divakar'     1000    10        0.0013951
    'solution_bsxfun_cumsum_Divakar'         1000    10        0.0015138
    'solution_bsxfun_sprintf_Divakar'        1000    10        0.0011496
    'solution_eval_loops_CSTLink'            1000    10        0.0061538
    'solution_loops_CSTLink'                 1000    10        0.0020528
    'solution_mex_Amro'                      1000    10        0.0019629
    'solution_mex_chappjc'                   1000    10       0.00051825
    'solution_mex_omp_Amro'                  1000    10       0.00085117
    'solution_mex_omp_chappjc'               1000    10       0.00025825
    'solution_sscanf_Divakar'                1000    10        0.0078551
    'solution_sscanf_char_LuisMendo'         1000    10        0.0031104
    'solution_textscan_sprintf_chappjc'      1000    10        0.0016144
    'func_eval_cellfun'                     10000    10          0.05772
    'func_eval_loop'                        10000    10         0.061705
    'func_eval_sprintf'                     10000    10          0.54464
    'func_eval_strjoin'                     10000    10          0.57007
    'func_sscanf_cellfun'                   10000    10           0.1192
    'func_sscanf_loop'                      10000    10         0.068017
    'func_sscanf_sprintf'                   10000    10         0.019622
    'func_sscanf_strjoin'                   10000    10         0.038232
    'func_str2num_cellfun'                  10000    10          0.13811
    'func_str2num_loop'                     10000    10          0.14812
    'func_str2num_sprintf'                  10000    10          0.48726
    'func_str2num_strjoin'                  10000    10          0.50528
    'func_textscan_cellfun'                 10000    10          0.17378
    'func_textscan_loop'                    10000    10           0.1241
    'func_textscan_sprintf'                 10000    10         0.016595
    'func_textscan_strjoin'                 10000    10         0.035599
    'func_voigt_loop'                       10000    10         0.012136
    'solution_bsxfun_bytestream_Divakar'    10000    10         0.015908
    'solution_bsxfun_cumsum_Divakar'        10000    10          0.02301
    'solution_bsxfun_sprintf_Divakar'       10000    10         0.014862
    'solution_eval_loops_CSTLink'           10000    10         0.063188
    'solution_loops_CSTLink'                10000    10         0.020153
    'solution_mex_Amro'                     10000    10         0.019252
    'solution_mex_chappjc'                  10000    10        0.0051221
    'solution_mex_omp_Amro'                 10000    10        0.0066551
    'solution_mex_omp_chappjc'              10000    10        0.0014584
    'solution_sscanf_Divakar'               10000    10         0.096345
    'solution_sscanf_char_LuisMendo'        10000    10         0.031047
    'solution_textscan_sprintf_chappjc'     10000    10         0.016736
    'func_eval_cellfun'                     1e+05    10          0.78876
    'func_eval_loop'                        1e+05    10           0.6119
    'func_eval_sprintf'                     1e+05    10           6.7603
    'func_eval_strjoin'                     1e+05    10           5.7204
    'func_sscanf_cellfun'                   1e+05    10           1.2096
    'func_sscanf_loop'                      1e+05    10          0.68303
    'func_sscanf_sprintf'                   1e+05    10          0.21101
    'func_sscanf_strjoin'                   1e+05    10          0.55226
    'func_str2num_cellfun'                  1e+05    10            1.411
    'func_str2num_loop'                     1e+05    10           1.8229
    'func_str2num_sprintf'                  1e+05    10           6.1474
    'func_str2num_strjoin'                  1e+05    10            7.551
    'func_textscan_cellfun'                 1e+05    10           2.5898
    'func_textscan_loop'                    1e+05    10           1.7934
    'func_textscan_sprintf'                 1e+05    10          0.25421
    'func_textscan_strjoin'                 1e+05    10           1.1762
    'func_voigt_loop'                       1e+05    10          0.25602
    'solution_bsxfun_bytestream_Divakar'    1e+05    10            0.265
    'solution_bsxfun_cumsum_Divakar'        1e+05    10          0.35656
    'solution_bsxfun_sprintf_Divakar'       1e+05    10          0.23481
    'solution_eval_loops_CSTLink'           1e+05    10          0.86425
    'solution_loops_CSTLink'                1e+05    10          0.28436
    'solution_mex_Amro'                     1e+05    10          0.27104
    'solution_mex_chappjc'                  1e+05    10         0.078901
    'solution_mex_omp_Amro'                 1e+05    10         0.096553
    'solution_mex_omp_chappjc'              1e+05    10          0.03679
    'solution_sscanf_Divakar'               1e+05    10           1.3818
    'solution_sscanf_char_LuisMendo'        1e+05    10          0.43994
    'solution_textscan_sprintf_chappjc'     1e+05    10          0.21271
    'func_eval_cellfun'                     5e+05    10           3.7658
    'func_eval_loop'                        5e+05    10           3.8106
    'func_eval_sprintf'                     5e+05    10           32.383
    'func_eval_strjoin'                     5e+05    10           40.451
    'func_sscanf_cellfun'                   5e+05    10           8.5704
    'func_sscanf_loop'                      5e+05    10            4.707
    'func_sscanf_sprintf'                   5e+05    10           1.4362
    'func_sscanf_strjoin'                   5e+05    10           2.8301
    'func_str2num_cellfun'                  5e+05    10           9.6439
    'func_str2num_loop'                     5e+05    10           10.453
    'func_str2num_sprintf'                  5e+05    10           35.818
    'func_str2num_strjoin'                  5e+05    10           37.277
    'func_textscan_cellfun'                 5e+05    10           12.418
    'func_textscan_loop'                    5e+05    10           8.8237
    'func_textscan_sprintf'                 5e+05    10           1.2793
    'func_textscan_strjoin'                 5e+05    10           2.6496
    'func_voigt_loop'                       5e+05    10           1.2486
    'solution_bsxfun_bytestream_Divakar'    5e+05    10            1.324
    'solution_bsxfun_cumsum_Divakar'        5e+05    10           1.8229
    'solution_bsxfun_sprintf_Divakar'       5e+05    10           1.2113
    'solution_eval_loops_CSTLink'           5e+05    10           6.5759
    'solution_loops_CSTLink'                5e+05    10           1.4583
    'solution_mex_Amro'                     5e+05    10           1.3718
    'solution_mex_chappjc'                  5e+05    10          0.39711
    'solution_mex_omp_Amro'                 5e+05    10          0.48046
    'solution_mex_omp_chappjc'              5e+05    10          0.48174
    'solution_sscanf_Divakar'               5e+05    10           7.7943
    'solution_sscanf_char_LuisMendo'        5e+05    10           2.2332
    'solution_textscan_sprintf_chappjc'     5e+05    10           1.2399
    'func_eval_cellfun'                     1e+06    10           7.3884
    'func_eval_loop'                        1e+06    10           7.5519
    'func_eval_sprintf'                     1e+06    10           69.868
    'func_eval_strjoin'                     1e+06    10           71.964
    'func_sscanf_cellfun'                   1e+06    10           15.061
    'func_sscanf_loop'                      1e+06    10           8.4163
    'func_sscanf_sprintf'                   1e+06    10           2.7099
    'func_sscanf_strjoin'                   1e+06    10           5.1453
    'func_str2num_cellfun'                  1e+06    10            17.42
    'func_str2num_loop'                     1e+06    10           18.165
    'func_str2num_sprintf'                  1e+06    10           60.902
    'func_str2num_strjoin'                  1e+06    10           63.579
    'func_textscan_cellfun'                 1e+06    10           20.423
    'func_textscan_loop'                    1e+06    10           14.309
    'func_textscan_sprintf'                 1e+06    10           2.2853
    'func_textscan_strjoin'                 1e+06    10           4.5216
    'func_voigt_loop'                       1e+06    10           2.2443
    'solution_bsxfun_bytestream_Divakar'    1e+06    10           2.3495
    'solution_bsxfun_cumsum_Divakar'        1e+06    10           3.3843
    'solution_bsxfun_sprintf_Divakar'       1e+06    10           2.0311
    'solution_eval_loops_CSTLink'           1e+06    10           7.7524
    'solution_loops_CSTLink'                1e+06    10           2.4947
    'solution_mex_Amro'                     1e+06    10            2.486
    'solution_mex_chappjc'                  1e+06    10          0.76551
    'solution_mex_omp_Amro'                 1e+06    10          0.92226
    'solution_mex_omp_chappjc'              1e+06    10          0.88736
    'solution_sscanf_Divakar'               1e+06    10           19.673
    'solution_sscanf_char_LuisMendo'        1e+06    10           3.8578
    'solution_textscan_sprintf_chappjc'     1e+06    10           2.0074

接下来...

X5550 24GB R2014b

顺序不同,但差异再次微不足道。

输入图像描述

输入图像描述

定时超过30000个字符的限制,但如果需要,我可以在其他地方发布它们。 顺序是清楚的。

我建议CST-Link忽略所有这些测量结果来进行决策。


当然,MEX解决方案是最好的。上面的解决方案使用std::string::const_iterator istr非常快,使用OpenMP更快。GCC 4.9.1(pthreads)和VS2013对于此代码具有可比性的性能。线程化源代码在此处


你尝试过不同的C++编译器吗?由于某种原因,VS2013比GCC慢至少两倍(我使用的是最新的MinGW-w64 GCC 4.9.1,从这里下载)。线程版本甚至更糟糕。 - Amro
@Amro,是istringstream还是这个?但是,我没有和GCC进行比较,尽管我安装了MinGW-w64(与您的版本相同,除了win32threads版本),因为我正在进行一个ffmpeg构建。我可以稍后尝试。顺便说一下,我没有时间让这段代码变得漂亮,这里没有聪明的地方。 - chappjc
不,我指的是带有 stringstream 的版本。我还没有使用您的修改重新运行基准测试,但我确实看到它在解析字符串方面会更快。 - Amro
我更新了我的测试结果。你修改后的版本是最快的,恭喜! - Amro
漂亮的新图表。所有标题都说2014b,但答案中的标题却说i7是2014a? - Ben Voigt
@BenVoigt 标题是正确的,图表标题是错误的。 - chappjc

5

方法 #1

这种方法从广义上分为两部分。第一部分得到一个大字符串,其中包含单元数组中所有字符,并用下划线分隔两个单元格,这基本上是通过cumsum实现的。第二部分基于bsxfun以所需格式获得所需的数字输出。

代码如下 -

function out = solution_cumsum_bsxfun(list_of_words)

N = 1 + sum(list_of_words{1}=='_'); %// Number of "words" per cell
lens = cellfun('length',list_of_words); %// No. of chars [lengths] in each cell
tlens = sum(lens); %// Total number of characters [total of lengths]
cumlens = cumsum(lens); %// Cumulative lengths

%// Create an array of ones and zeros. 
%// The length of this array would be equal to sum of characters in all cells. 
%// The ones would be at the positions where new cells start, zeros otherwise
startpos_newcell(1,tlens)=0;
startpos_newcell(cumlens(1:end-1)+1)=1;

%// Calculate new positions for all characters in the cell array with 
%// places/positions left between two cells for putting underscores
newpos = (1:tlens) + cumsum(startpos_newcell);

%// Create one long string that has all the characters from the cell arary
%// with underscores separating cells
one_str(newpos) = [list_of_words{:}];
one_str(cumlens + [1:numel(cumlens)]') = '_'; %//'#

pos_us = find(one_str=='_'); %// positions of underscores
wordend_idx = pos_us - [1:numel(pos_us)]; %// word end indices
wordlens = [wordend_idx(1) diff(wordend_idx)]; %// word lengths
max_wordlens = max(wordlens); %// maximum word length

%// Create mask where digit characters are to be placed
mask = bsxfun(@ge,[1:max_wordlens]',[max_wordlens+1-wordlens]); %//'#

%// Create a numeric array with columns for each word and each row holding a digit.
%// The most significant digits to least significant going from top to bottom
num1(max_wordlens,size(mask,2)) = 0;
num1(mask) = one_str(one_str~='_') - 48;

%// Finally get the desired output converting each column to a single
%// number, reshaping to desired size and scaling down by a factor of 1000
out = reshape(10.^(max_wordlens-4:-1:-3)*num1,N,[]).'; %//'#

return;

方法2

这是方法1的一个轻微变化,它使用sprintf处理第一部分的工作。现在,我看到了它在@chappjc的解决方案中的实际应用后,想到了这个想法。我感谢他让我在这个修改版本中使用它。

这是代码 -

function out = solution_sprintf_bsxfun(list_of_words)

N = 1 + sum(list_of_words{1}=='_'); %// Number of "words" per cell

%// Create one long string that has all the characters from the cell arary
%// with underscores separating cells
one_str = sprintf('%s_',list_of_words{:});

pos_us = find(one_str=='_'); %// positions of underscores
wordend_idx = pos_us - [1:numel(pos_us)]; %// word end indices
wordlens = [wordend_idx(1) diff(wordend_idx)]; %// word lengths
max_wordlens = max(wordlens); %// maximum word length

%// Create mask where digit characters are to be placed
mask = bsxfun(@ge,[1:max_wordlens]',[max_wordlens+1-wordlens]); %//'#

%// Create a numeric array with columns for each word and each row holding a digit.
%// The most significant digits to least significant going from top to bottom
num1(max_wordlens,size(mask,2)) = 0;
num1(mask) = one_str(one_str~='_') - 48;

%// Finally get the desired output converting each column to a single
%// number, reshaping to desired size and scaling down by a factor of 1000
out = reshape(10.^(max_wordlens-4:-1:-3)*num1,N,[]).'; %//'#

return;

第三种方法

这是一种全新的方法,基于getByteStreamFromArray -

function out = solution_bytstrm_bsxfun(list_of_words)

allchars = [list_of_words{:}];
digits_array = getByteStreamFromArray(allchars);

%// At my 32-bit system getByteStreamFromArray gets the significant digits 
%// from index 65 onwards. Thus, we need to crop/index it accordingly
digits_array = digits_array(65:65+numel(allchars)-1) - 48;
% --------------------------------------------------------------------
N = 1 + sum(list_of_words{1}=='_'); %// Number of "words" per cell
lens = cellfun('length',list_of_words); %// No. of chars [lengths] in each cell
cumlens = cumsum(lens)'; %//'# Cumulative lengths
% ----------------------------------------------------------
pos_us = find(digits_array==47);
starts = [[1 cumlens(1:end-1)+1];reshape(pos_us+1,N-1,[])];
ends = [reshape(pos_us-1,N-1,[]) ; cumlens];
gaps = ends(:) - starts(:) + 1;

maxg = max(gaps);
mask1 = bsxfun(@lt,maxg-gaps',[1:maxg]');

num_array(maxg,numel(lens)*N)=0;
num_array(mask1) = digits_array(digits_array~=47);
out = reshape(10.^(maxg-4:-1:-3)*num_array,N,[]).';

return;

以下是上述方法的GPU版本。 方法#4
function out = soln_sprintf_bsxfun_gpu(list_of_words)

N = 1 + sum(list_of_words{1}=='_'); %// Number of "words" per cell

%// Create one long string that has all the characters from the cell arary
%// with underscores separating cells. Now this one uses sprintf as
%// firstly proposed in @chappjc's solution and he has agreed to let me use
%// it, so appreciating his help on this.
digits_array = gpuArray(single(sprintf('%s_',list_of_words{:})));
digits_array = digits_array - 48;

mask_us = digits_array==47; %// mask of underscores
pos_us = find(mask_us);

wordend_idx = pos_us - gpuArray.colon(1,numel(pos_us)); %// word end indices
wordlens = [wordend_idx(1) diff(wordend_idx)]; %// word lengths
max_wordlens = max(wordlens); %// maximum word length

%// Create a numeric array with columns for each word and each row holding a digit.
%// The most significant digits to least significant going from top to bottom
num1 =  single(zeros(max_wordlens,numel(pos_us),'gpuArray')); %//'
num1(bsxfun(@ge,gpuArray.colon(1,max_wordlens)',...
    max_wordlens+1-single(wordlens))) = digits_array(~mask_us); %//'

%// Finally get the desired output converting each column to a single
%// number, reshaping to desired size and scaling down by a factor of 1000
outg = reshape(10.^(max_wordlens-4:-1:-3)*num1,N,[]).'; %//'#
out = gather(outg);

返回;

方法 #5

function out = soln_bytstrm_bsxfun_gpu(list_of_words)

us_ascii_num = 95;
allchars = [list_of_words{:}];

%// At my 32-bit system getByteStreamFromArray gets the significant digits 
%// from index 65 onwards. Thus, we need to crop/index it accordingly
alldigits = getByteStreamFromArray(allchars);
digits_array1 = gpuArray(alldigits(65:65+numel(allchars)-1));
% --------------------------------------------------------------------
lens = cellfun('length',list_of_words); %// No. of chars [lengths] in each cell
N = sum(digits_array1(1:lens(1))==us_ascii_num)+1; %// Number of "words" per cell
lens = gpuArray(lens);
cumlens = cumsum(lens)'; %//'# Cumulative lengths
% ----------------------------------------------------------
mask_us = digits_array1==us_ascii_num; %// mask of underscores
pos_us = find(mask_us);
starts = [[1 cumlens(1:end-1)+1];reshape(pos_us+1,N-1,[])];
ends = [reshape(pos_us-1,N-1,[]) ; cumlens];
gaps = ends(:) - starts(:) + 1;

maxg = max(gaps);
mask1 = bsxfun(@lt,maxg-gaps',[1:maxg]');

num_array = zeros(maxg,numel(lens)*N,'gpuArray'); %//'
num_array(mask1) = digits_array1(~mask_us)-48;
out = reshape(10.^(maxg-4:-1:-3)*num_array,N,[]).'; %//'
out = gather(out);

return;

1
@chappjc 我相信这是因为bsxfun需要占用大量内存,而我的低RAM系统无法承受。不过,还是非常感谢您进行测试! - Divakar
@Divakar 是的,就是那个。 - user2271770
@CST-Link 10.^(maxg-4:-1:-3) 内部已经处理了 除以1000 的操作。如果您在编辑代码之前咨询一下就更好了 :) - Divakar
哦,该死,那我很抱歉。我的错。 :-) - user2271770
1
恭喜!你赚到了! - chappjc
显示剩余14条评论

3
以下解决方案似乎有效:
function array_of_numbers = char_and_sscanf_solution(list_of_words)

s = char(list_of_words);
s(s==95) = 32; %// 95 is '_'; 32 is ' '
s = [ s repmat(32, numel(list_of_words), 1) ];
array_of_numbers = reshape(sscanf(s.','%i '), [], numel(list_of_words)).'/1000;

使用referee_timing.mreferee_test_case.m进行基准测试的结果如下:
Generating 10000-words test case...
Timing 10000-words test case...
  eval_and_loops_solution: 0.190642[s]
  single_sscanf_solution: 0.234413[s]
  approach1: 0.073901[s]
  char_and_sscanf_solution: 0.068311[s]

Generating 100000-words test case...
Timing 100000-words test case...
  eval_and_loops_solution: 1.957728[s]
  single_sscanf_solution: 2.426764[s]
  approach1: 0.766020[s]
  char_and_sscanf_solution: 0.706387[s]

Generating 1000000-words test case...
Timing 1000000-words test case...
  eval_and_loops_solution: 18.975746[s]
  char_and_sscanf_solution: 7.147229[s]

计算机信息:

Matlab R2010b
Windows 7 Home Premium 64位Service Pack 1
Pentium(R)Dual Core CPU T4300 2.10 GHz
4 GB RAM


1
非常干净的解决方案,顺便一提。+1 - chappjc
@CST-Link 我认为这很好...但它变得复杂了 :-) 无论如何,我觉得奇怪的是有些解决方案在我的系统上需要这么长时间。 - Luis Mendo
@CST-Link 你说得对,这是一个很好的改进。然而,我的电脑/Matlab版本似乎给出了如此奇怪的时间,以至于我认为更新它们不值得。也许你可以试试?也许在你的电脑上发布一个答案,包括所提议的函数的时间?如果你这样做,请在我的解决方案中包括我在第一条评论中提到的优化(使用下划线的ASCII码)。 - Luis Mendo
1
不同长度的随机行似乎会影响您创建s的过程。由于char使用空格填充不等长的行,因此在大多数行上,_的连接不是紧接着最后一个数字。我不确定有什么好的解决方法,除了我的sprintf技巧。;) - chappjc
@CST-Link 不,我的函数隐含地假设单词长度相等。请参考chappjc上面的评论。我会研究一下。 - Luis Mendo
显示剩余9条评论

3
我会将一个逗号分隔的列表输入应用于 sprintf 函数来生成一个单一、完全分隔的 1D 字符串(每行/字符串末尾都有分隔符),然后使用 textscan 函数提取整数:

extractIntsSprintfTextScan.m

function M = extractIntsSprintfTextScan(list_of_words)

% optimized lines, see below for explanation of each op
M = textscan(sprintf('%s_',C{:}),'%.0f', 'Delimiter','_');
M = reshape(M{1}, [], numel(C)).';

% cell to string, adding _ suffix
% s = sprintf('%s_',list_of_words{:});

% extract integers given _ as delimiter
% C = textscan(s,'%u','Delimiter','_','CollectOutput',1); % can also use %d for signed
% C = textscan(s,'%.0f_','CollectOutput',1); % a little faster to put _ in the pattern

% matrix form
% M = reshape(C{1},[],numel(list_of_words)).'/1000; % remove transpose for faster output

end

基准测试(之前的计时现在已过时,请参见Amro的基准测试帖子中的sprintf + textscan解决方案)

机器

MATLAB R2014b 64位
Windows 7 64位
24 GB RAM
双路 Xeon X5550(2.67GHZ,8个物理核心)

更新:将输出类型从整数类型更改为双精度类型。重新运行基准测试。
更新2:将格式说明符从“%f”更改为“%.0f”,这可能使扫描加快,因为不需要小数。增加N = 100e3;(请参见GitHub Gist)。
更新3:使用CST-Link计时函数版本2进行新的基准测试(请参见带有referee_timing.m建议用法的newGitHub Gist)。
更新4:添加Luis的解决方案。请注意,由于数据是随机生成的,结果会波动。
更新5:优化调整--请参见Amro的基准测试帖子。


1
哇,你的机器真是太棒了!你能澄清一下你用的是哪个“N”吗?或者尝试不同的“N”值?我用“N”得到了奇怪的变化。最后,人们可能不知道“Jon”是谁 :-) - Luis Mendo
@LuisMendo 这是个有趣的小玩具!我只是将N从6e4改为1e5(请参见GitHub Gist获取实际脚本)。我感觉由于我拥有如此多的RAM和核心,其他基准测试可能不会强调某些代码方面。 - chappjc
@CST-Link,我已经使用你的新基准函数(非常好的设置!)并放置了测试脚本在这里。你应该真正使用正式的赏金系统来发布悬赏,而且30天有点长,我不是因为我喜欢我的结果才这么说的。 :) - chappjc
我的机器在某些解决方案中无法处理大的 N,因此我无法进行比较。您介意将我的更正后的解决方案添加到您的测试中吗? - Luis Mendo
@LuisMendo 当然不是。干得好,Luis!我很快会更新。 - chappjc
显示剩余5条评论

2

在MATLAB的假期氛围下,这是一种高度向量化的解决方案:

function M = func_voigt_loop(C)
    S = sprintf('_%s', C{:});
    digitpos = [find(S(2:end) == '_'), numel(S)];
    M = zeros(size(digitpos));
    place = 1;
    while 1
        digits = S(digitpos);
        mask = double(digits ~= '_');
        M = M + mask.*(digits - '0') * place;
        place = place * 10;
        digitpos = digitpos - mask;
        if ~any(mask); break; end
    end
    M = reshape(M, [], numel(C))';
end

这只是几行代码,易于理解(提取每个数字的个位数,加上十位数等),不使用任何“奇怪”的函数,如evaltextscan。它也非常快。

这个想法类似于我之前为在CSV文件中处理整列数据的datenum而开发的东西,MATLAB版本即使指定了特定的模式,速度也非常慢。后来的MATLAB版本大大改进了datenum,但我的手动调整版本仍然轻松击败它。


1
好的解决方案。+1 显然,我喜欢sprintf部分和每个数字*10的方法,因为这就是我做MEX恶作剧答案的方式(嘲笑使用MATLAB进行最佳性能的想法)。然而,我认为,远非奇特,textscan现在是MATLAB中主流的文本处理函数。如果您浏览一下MATLAB最近几个版本的发布说明,就会发现MathWorks一直在专注于将textscan构建成一个非常快速的文本扫描器,其语法与sscanf类似。 - chappjc
这也相当快。以下是我在我的机器上进行快速测试(大小=1e4 x 10)的结果:http://i.stack.imgur.com/1HD7H.png。正如我之前所说,结果会因运行而异,因此在做出决定之前,请务必在您的机器上进行测试! - Amro
@chappjc:我有点用“奇特”来表示非可移植性。这个答案中的所有内容都可以在其他语言中轻松复制。 - Ben Voigt
@BenVoigt:当然,你对于SIMD类型的向量化是正确的。当数据足够大以证明开销时,大多数矩阵操作会隐式提供此功能。 - Amro
1
@chappjc:感谢您抽出时间运行所有这些测试。我们肯定有很多好的实现可供选择! - Amro
显示剩余8条评论

2

接受挑战!这是我目前最快的实现方式,是一个C++ MEX文件 :)

solution_mex.cpp

#include "mex.h"
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>

namespace {

// get i-th string from cell-array of strings
std::string getString(const mxArray *cellstr, mwIndex idx)
{
    mxArray *arr = mxGetCell(cellstr, idx);
    if (arr == NULL) mexErrMsgIdAndTxt("mex:err", "null/uninitialized");
    if (!mxIsChar(arr)) mexErrMsgIdAndTxt("mex:err", "not a string");
    char *cstr = mxArrayToString(arr);
    if (cstr == NULL) mexErrMsgIdAndTxt("mex:err", "null");
    std::string str(cstr);
    mxFree(cstr);
    return str;
}

// count of numbers in char-delimited string
mwSize count_numbers(const std::string &s)
{
    return std::count(s.begin(), s.end(), '_') + 1;
}

// parse numbers
template <typename T>
void parseNumbers(const mxArray *cellstr, const mwSize len, std::vector<T> &v)
{
    // cell-array of strings
    std::vector<std::string> vs;
    vs.reserve(len);
    for (mwIndex idx=0; idx<len; ++idx) {
        vs.push_back(getString(cellstr, idx));
    }

    // join vector of strings into one
    std::stringstream ss;
    std::copy(vs.begin(), vs.end(),
        std::ostream_iterator<std::string>(ss, "_"));

    // split string into numbers (separated by single-char delimiter)
    T num;
    while (ss >> num) {
        v.push_back(num);
        ss.ignore(1);
    }
}

};

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // validate inputs
    if (nrhs!=1 || nlhs>1) mexErrMsgIdAndTxt("mex:err", "wrong num args");
    if (!mxIsCell(prhs[0])) mexErrMsgIdAndTxt("mex:err", "not cell");

    // allocate output matrix
    mwSize len = mxGetNumberOfElements(prhs[0]);
    mwSize sz = (len > 0) ? count_numbers(getString(prhs[0],0)) : 0;
    plhs[0] = mxCreateNumericMatrix(sz, len, mxDOUBLE_CLASS, mxREAL);
    if (plhs[0] == NULL) mexErrMsgIdAndTxt("mex:err", "null");
    if (len == 0 || sz == 0) return;

    // parse cell array into numbers
    std::vector<int> v;
    v.reserve(len*sz);
    parseNumbers(prhs[0], len, v);
    if (v.size() != (len*sz)) mexErrMsgIdAndTxt("mex:err", "wrong size");

    // copy numbers into output matrix
    std::copy(v.begin(), v.end(), mxGetPr(plhs[0]));
}

这段代码易于阅读;我尽可能使用标准STL库(没有奇怪的技巧),并添加了大量检查和输入验证,只要您按照问题描述中的输入格式进行操作,那么它应该是健壮的。

稍后我会提供一些基准测试结果,但现在您可以自己测试并与其他解决方案进行比较...

请注意,上述MEX函数返回大小为n_numbers * n_words的矩阵,因此您需要对结果进行转置。

下面是一个包装的M函数,可以在评委程序下运行:

solution_mex.m

function array_of_numbers = mex_solution(list_of_words)
    array_of_numbers = solution_mex(list_of_words).';
end

编辑#1

让我们简化代码;这个版本通过逐个处理字符串并将结果直接放入输出矩阵中,使用了更少的内存:

solution_mex.cpp

#include "mex.h"
#include <string>
#include <sstream>
#include <algorithm>

namespace {
std::string getString(const mxArray *cellstr, const mwIndex idx)
{
    // get i-th string from cell-array of strings
    mxArray *arr = mxGetCell(cellstr, idx);
    if (!arr || !mxIsChar(arr)) mexErrMsgIdAndTxt("mex:err", "not a string");
    char *cstr = mxArrayToString(arr);
    if (cstr == NULL) mexErrMsgIdAndTxt("mex:err", "null");
    std::string str(cstr);
    mxFree(cstr);
    return str;
}

mwSize count_numbers(const std::string &s)
{
    // count of numbers in char-delimited string
    return std::count(s.begin(), s.end(), '_') + 1;
}
};

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // validate inputs
    if (nrhs!=1 || nlhs>1) mexErrMsgIdAndTxt("mex:err", "wrong num args");
    if (!mxIsCell(prhs[0])) mexErrMsgIdAndTxt("mex:err", "not a cell");

    // determine sizes
    const mxArray *cellstr = prhs[0];
    const mwSize n_words = mxGetNumberOfElements(cellstr);
    const mwSize n_nums = (n_words > 0) ?
        count_numbers(getString(cellstr,0)) : 0;

    // allocate output matrix
    plhs[0] = mxCreateDoubleMatrix(n_nums, n_words, mxREAL);
    if (plhs[0] == NULL) mexErrMsgIdAndTxt("mex:err", "null");
    if (n_words == 0 || n_nums == 0) return;
    double *out = mxGetPr(plhs[0]);

    // extract numbers from strings
    for (mwIndex idx=0, i=0; idx<n_words; ++idx) {
        std::istringstream ss(getString(cellstr, idx));
        int num;
        while(ss >> num) {
            out[i++] = num;
            ss.ignore(1);
        }
    }
}

编辑#2(OpenMP)

接下来,让我们将其变成多线程的。我们可以使用OpenMP隐式地实现,只需添加两行代码即可!我正在对每个字符串进行并行化处理。

首先,我们添加omp parallel for指示符,然后将索引变量i设为每个线程私有,这样线程就知道起始列的索引。

在上一个编辑版中,只需用以下代码替换最后一个循环:

// extract numbers from strings
#pragma omp parallel for
for (mwIndex idx=0; idx<n_words; ++idx) {
    mwIndex i = idx*n_nums;  // starting index for i-th column
    std::istringstream ss(getString(cellstr, idx));
    int num;
    while(ss >> num) {
        out[i++] = num;
        ss.ignore(1);
    }
}

我正在Windows x64上运行R2014a,尝试使用VS2013和MinGW-w64 GCC 4.9.1进行编译。需要指出的是,使用GCC编译的版本比目前所有解决方案都要快得多:

% compile with MinGW-w64
>> mex -largeArrayDims -f mingwopts.bat solution_mex.cpp -output solution_mex_gcc

% set appropriate number of threads
>> setenv('OMP_NUM_THREADS','4');

% quick benchmark
>> timeit(@() solution_mex_gcc(repmat({'02_04_04_52_23_14_54_672_0'},1e6,1)).')
ans =
    0.6658

为了完整起见,您应该提供一个MATLAB包装器,至少完成其余的操作(转置和除以1000)。此外,这并不完全是我想要的;这就是为什么我指定“MATLAB本地”的原因。:-D 但是您的答案仍然受到欢迎。 - user2271770
@Amro 嗯,我自己也快要放弃MATLAB了,在我即将提出的最后一个解决方案中:不使用函数调用。或者可能是4个。:-) 但是,为了公平起见,我想将赏金奖励授予MATLAB标准函数和语言代码。 - user2271770
@Amro 也许你也可以看看我的位操作解决方案。它是纯MATLAB编写的,我很好奇在你的机器上会表现得如何。 - user2271770
@CST-Link:我正在一台核心i7的笔记本电脑上运行,但我相信如果你在像chappjc那样强大的机器上运行它,差异会更大。如果你有足够的RAM,请增加数据大小,你不会耗尽内存。如果你有必要的CPU核心,也可以使用更多线程 :) 我还有更多基准测试,稍后会发布它们。 - Amro
1
@Divakar 不,就我而言,我们只是为了好玩而胡闹。 - chappjc
显示剩余9条评论

2

(最新提议)

这种方法消除了我反MATLAB解决方案中最后一个与MATLAB相关的部分;纯字节扫描,循环内嵌循环,内存分配等操作:

%'all_loops.m'
function array_of_numbers = all_loops(list_of_words)

        %'Precalculate important numbers'
        n_numbers = 1 + sum(list_of_words{1}=='_');
        n_words   = numel(list_of_words);

        %'Allocate memory'
        array_of_numbers = zeros(n_numbers, n_words);
        slice_of_numbers = zeros(n_numbers, 1);

        %'Loop trough chunks of cell array'
        for k = 1:n_words
                str     = list_of_words{k};
                pos_max = size(str, 2);
                value   = 0;
                index   = 1;

                for pos = 1:pos_max
                        if str(pos) == '_'
                                slice_of_numbers(index) = value;
                                value                   = 0;
                                index                   = index + 1;
                        else
                                value = 10*value + (str(pos) - '0');
                        end;
                        slice_of_numbers(index) = value; %'almost forgot'
                end;

                array_of_numbers(:, k) = slice_of_numbers;
        end;

         %'This is a waste of memory, but is kind of required'
        array_of_numbers = transpose(array_of_numbers / 1000);

end

(基准测试) 以下配置信息获取自configinfo.m

MATLAB configuration information                    CPU: x86 Family 6 Model 58 Stepping 9, GenuineIntel
This data was gathered on: 24-Oct-2014 14:19:31     The measured CPU speed is: 2600 MHz
MATLAB version: 7.14.0.739 (R2012a)                 Number of processors: 4
MATLAB root: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx       RAM: 3289 MB
MATLAB accelerator enabled                          Swap space: 6576 MB
MATLAB JIT: enabled                                 Microsoft Windows 7
MATLAB assertions: disabled                         Number of cores: 2
MATLAB Desktop: enabled                             Number of threads: 2

以下是获取的结果(第3次运行):

Generating 10000-words test case...
Timing 1000000-words test case...
  approach4: Error - Out of memory. Type HELP MEMORY for your options.
  approach1: Error - Out of memory. Type HELP MEMORY for your options.
  single_sscanf_solution: Error - Out of memory. Type HELP MEMORY for your options.
  char_and_sscanf_solution: 5.076296[s]
  extractIntsSprintfTextScan: 4.328066[s]
  all_loops: 1.795730[s]
  eval_and_loops_solution: 10.027541[s]
Generating 100000-words test case...
Timing 100000-words test case...
  approach4: 0.252107[s]
  approach1: 0.370727[s]
  single_sscanf_solution: 1.364936[s]
  char_and_sscanf_solution: 0.515599[s]
  extractIntsSprintfTextScan: 0.444586[s]
  all_loops: 0.179575[s]
  eval_and_loops_solution: 1.010240[s]
Generating 10000-words test case...
Timing 10000-words test case...
  approach4: 0.026642[s]
  approach1: 0.039550[s]
  single_sscanf_solution: 0.136711[s]
  char_and_sscanf_solution: 0.049708[s]
  extractIntsSprintfTextScan: 0.042608[s]
  all_loops: 0.017636[s]
  eval_and_loops_solution: 0.099111[s]

你可能会注意到最后一步之间的差异,即“生成10000…”和“计时1000000…”;为了减少占用的内存(否则在生成测试用例时会失败),我使用了repmat(referee_test_case(1e4), 100, 1)而不是referee_test_case(1e6)


你能为我解决方案中添加的approach4.m增加一些基准测试吗?非常抱歉给你添麻烦了!:) - Divakar
@Divakar,“approach4.m”的时间已经添加。您能否发布自己的计时测试?我很好奇。 - user2271770
我对目前基于timeit的基准测试有所疑虑,因为它在转移到下一个方法之前没有清除上一个方法的输出。这在内存不足错误中很明显。因此,我创建了一个不同的基准测试代码,并将基于我的系统配置的结果上传到此处 - http://pastebin.com/1EucNwYB。你认为呢? - Divakar
@Divakar,看到代码在你的系统上的表现会很不错。 :-) - user2271770
顺便说一下,我们可以通过使用repmat(referee_test_case(1e4), 100, 1)而不是repmat(referee_test_case(1e5), 10, 1)来降低百万次测试的内存消耗。 - user2271770
显示剩余12条评论

2

基准测试

以下是这个基准测试所用的基准代码需要注意的几点。这与Amro的基准代码相同,但进行了以下更改 -

  • 将所有解决方案除以1000以保持解决方案之间的一致性。
  • 已删除有效性的错误检查。这不会影响运行时结果。
  • 数据大小(行数)扩展到1000000,因此我必须将每个单元格中的数字计数保持为8以将所有内容容纳在内存中。另外,我认为这将呈现出矢量化和循环解决方案之间的公正比较。
  • 避免使用基于Mex的解决方案,但如果有人愿意将这些基准解决方案与那些基于Mex的解决方案一起包含,则我很乐意看到运行时间的比较。
  • 对于GPU代码的基准测试,使用gputimeit而不是timeit

这些代码已经打包并可在此处下载。在此中,使用bench_script.m作为主函数。

基准测试结果

enter image description here

enter image description here

           func               nrows    ncols      time  
__________________________    _____    _____    ________

'all_loops'                   10000    8        0.026996
'char_and_sscanf_solution'    10000    8        0.034492
'eval_and_loops_solution'     10000    8         0.22548
'extIntsSprintfTextScan'      10000    8        0.036889
'func_eval_cellfun'           10000    8         0.16483
'func_eval_loop'              10000    8          0.1845
'func_sscanf_cellfun'         10000    8         0.40217
'func_sscanf_loop'            10000    8         0.19508
'func_sscanf_sprintf'         10000    8        0.027505
'func_sscanf_strjoin'         10000    8         0.11128
'func_str2num_cellfun'        10000    8          0.4976
'func_str2num_loop'           10000    8          0.5303
'func_textscan_cellfun'       10000    8           0.547
'func_textscan_loop'          10000    8          0.3752
'func_textscan_sprintf'       10000    8        0.036699
'func_textscan_strjoin'       10000    8         0.12059
'single_sscanf_solution'      10000    8         0.17122
'soln_bytstrm_bsxfun_gpu'     10000    8        0.023365
'soln_sprintf_bsxfun_gpu'     10000    8        0.019986
'solution_bytstrm_bsxfun'     10000    8        0.031165
'solution_cumsum_bsxfun'      10000    8        0.047445
'solution_sprintf_bsxfun'     10000    8        0.028417
'all_loops'                   50000    8         0.13444
'char_and_sscanf_solution'    50000    8          0.1753
'eval_and_loops_solution'     50000    8          1.1242
'extIntsSprintfTextScan'      50000    8          0.1871
'func_eval_cellfun'           50000    8         0.82261
'func_eval_loop'              50000    8         0.91632
'func_sscanf_cellfun'         50000    8          2.0088
'func_sscanf_loop'            50000    8         0.97656
'func_sscanf_sprintf'         50000    8         0.13891
'func_sscanf_strjoin'         50000    8         0.56368
'func_str2num_cellfun'        50000    8          2.4786
'func_str2num_loop'           50000    8          2.6377
'func_textscan_cellfun'       50000    8          2.7452
'func_textscan_loop'          50000    8          1.8249
'func_textscan_sprintf'       50000    8         0.18556
'func_textscan_strjoin'       50000    8         0.60935
'single_sscanf_solution'      50000    8         0.90871
'soln_bytstrm_bsxfun_gpu'     50000    8         0.10591
'soln_sprintf_bsxfun_gpu'     50000    8        0.079611
'solution_bytstrm_bsxfun'     50000    8         0.18875
'solution_cumsum_bsxfun'      50000    8         0.27233
'solution_sprintf_bsxfun'     50000    8         0.16467
'all_loops'                   80000    8         0.21602
'char_and_sscanf_solution'    80000    8         0.27855
'eval_and_loops_solution'     80000    8          1.7997
'extIntsSprintfTextScan'      80000    8         0.29733
'func_eval_cellfun'           80000    8          1.3171
'func_eval_loop'              80000    8          1.4647
'func_sscanf_cellfun'         80000    8          3.2232
'func_sscanf_loop'            80000    8          1.5664
'func_sscanf_sprintf'         80000    8         0.22136
'func_sscanf_strjoin'         80000    8         0.89605
'func_str2num_cellfun'        80000    8          3.9688
'func_str2num_loop'           80000    8          4.2199
'func_textscan_cellfun'       80000    8          4.3841
'func_textscan_loop'          80000    8          2.9181
'func_textscan_sprintf'       80000    8         0.29494
'func_textscan_strjoin'       80000    8         0.97383
'single_sscanf_solution'      80000    8          1.4542
'soln_bytstrm_bsxfun_gpu'     80000    8         0.15528
'soln_sprintf_bsxfun_gpu'     80000    8         0.11911
'solution_bytstrm_bsxfun'     80000    8         0.28552
'solution_cumsum_bsxfun'      80000    8         0.43238
'solution_sprintf_bsxfun'     80000    8         0.24801
'all_loops'                   1e+05    8         0.26833
'char_and_sscanf_solution'    1e+05    8         0.34617
'eval_and_loops_solution'     1e+05    8          2.2465
'extIntsSprintfTextScan'      1e+05    8         0.37322
'func_eval_cellfun'           1e+05    8           1.641
'func_eval_loop'              1e+05    8          1.8339
'func_sscanf_cellfun'         1e+05    8           4.024
'func_sscanf_loop'            1e+05    8          1.9598
'func_sscanf_sprintf'         1e+05    8         0.27558
'func_sscanf_strjoin'         1e+05    8          1.1193
'func_str2num_cellfun'        1e+05    8          4.9592
'func_str2num_loop'           1e+05    8          5.2634
'func_textscan_cellfun'       1e+05    8          5.6636
'func_textscan_loop'          1e+05    8           3.981
'func_textscan_sprintf'       1e+05    8         0.36947
'func_textscan_strjoin'       1e+05    8           1.208
'single_sscanf_solution'      1e+05    8          1.8665
'soln_bytstrm_bsxfun_gpu'     1e+05    8         0.19389
'soln_sprintf_bsxfun_gpu'     1e+05    8         0.14588
'solution_bytstrm_bsxfun'     1e+05    8         0.35404
'solution_cumsum_bsxfun'      1e+05    8         0.54906
'solution_sprintf_bsxfun'     1e+05    8         0.30324

系统配置

MATLAB Version: 8.3.0.532 (R2014a)
Operating System: Ubuntu 14.04 LTS 64-bit
RAM: 4GB
CPU Model: Intel® Pentium® Processor E5400 (2M Cache, 2.70 GHz)
GPU Model: GTX 750Ti 2GB

configinfo.m输出(仅列出重要内容) -

MATLAB accelerator enabled
MATLAB JIT: enabled
MATLAB assertions: disabled
MATLAB Desktop: enabled
Java JVM: enabled
CPU: x86 Family 6 Model 23 Stepping 10, GenuineIntel
Number of processors: 2
CPU speed is: 2700 MHz
RAM: 4046992 kB
Swap space: 9760764 kB
Number of cores: 2
Number of threads: 2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接