【问题标题】:Loading chunks of large binary files in Matlab, quickly在 Matlab 中快速加载大块二进制文件
【发布时间】:2019-01-27 00:16:58
【问题描述】:

我有一些 int16 格式的大量数据文件(256 个通道,大约 75-1 亿个样本 = 每个文件约 40-50 GB)。它以平面二进制格式编写,因此结构类似于:CH1S1,CH2S1,CH3S1 ... CH256S1,CH1S2,CH2S2,...

我需要分别读取每个通道,过滤和偏移校正它,然后保存。我目前的瓶颈是加载每个频道,这大约需要 7-8 分钟......将其扩大 256 倍,而我正在寻找近 30 个小时来加载数据!我正在尝试智能地使用 fread,在读取每个通道时跳过字节;我在所有 256 个通道的循环中有以下代码来执行此操作:

offset = i - 1;
fseek(fid,offset*2,'bof');
dat = fread(fid,[1,nSampsTotal],'*int16',(nChan-1)*2);

仔细阅读,这通常是加载大型二进制文件部分内容的最快方式,但文件是否太大而无法更快地执行此操作?

我没有加载那么多数据...我正在使用的测试文件是 37GB,对于 256 个通道之一,我只为整个跟踪加载 149MB...也许是“跳过” fread 的功能不是最理想的?

系统详情:MATLAB 2017a,Windows 7,64 位,32GB RAM

【问题讨论】:

  • 如果您有能力一次性加载完整文件,请执行此操作。否则,请尝试加载大块并使用索引来保留您需要的部分,看看是否更快。
  • Q1) 为什么“需要分别读取每个频道”? Q2) 为什么不以更合理的格式存储数据,或者使用高性能语言暂时拆分数据,使用 R 过滤,然后使用高性能语言重新组装?
  • @Cris:一口气加载它会很棒,但我没有足够的 RAM (32GB)。加载大块不是很好,因为过滤的边缘伪影(除非我填充加载的块并重新组合,我可以这样做但想避免)。大多数情况下,我很困惑为什么 fread 的“跳过”功能这么慢......我读到的所有内容都告诉我,跳过字节是在 Matlab 中加载部分二进制文件的最快方法
  • @MarkSetchell:单独阅读不是必需的,但非常适合如上所述的过滤。对于存储,这是来自电生理设备的原始数据的格式。您建议使用哪种高性能语言? C?我的大部分经验是在 Matlab 和 Python 中,但我可以试一试......
  • 我使用的是带有 NVME SSD 驱动器的 Mac,它支持 2GB/s,因此将在 25 秒内读取 50GB 文件,并在 30-40 秒内写入。传统驱动器的运行速度可能会慢 10-15 倍左右,因此您可以期望在 15 分钟内拆分文件,然后在同一时间重新组合。不确定每个通道的处理需要多长时间,但如果每个通道的数据是分开的,大概可以在 4-8 个线程中轻松并行化它 - 正如我所建议的那样。

标签: matlab performance binaryfiles


【解决方案1】:

@CrisLuengo 的想法要快得多:本质上,将数据分块,加载每个块,然后将其拆分为单独的通道文件以节省 RAM。

这里是一些快速加载部分的代码,不到 1 分钟:

% fake raw data
disp('building... ');
nChan = 256;
nSampsTotal = 10e6;
tic; DATA = rand(nChan,nSampsTotal); toc;
fid = fopen('rawData.dat','w');
disp('writing flat binary file... ');
tic; fwrite(fid,DATA(:),'int16'); toc;
fclose(fid);

% compute the number of samples and chunks
chunkSize = 1e6;
nChunksTotal = ceil(nSampsTotal/chunkSize);


%% load by chunks
t1 = tic;
fid = fopen('rawData.dat','r');
dat = zeros(nChan,chunkSize,'int16');
chunkCnt = 1;
while 1
    tic
    if chunkCnt <= nChunksTotal
        % load the data
        fprintf('Chunk %02d/%02d: loading... ',chunkCnt,nChunksTotal);
        dat = fread(fid,[nChan,chunkSize],'*int16');
    else
        break;
    end
    toc;
    chunkCnt = chunkCnt + 1;
end
t = toc(t1); fprintf('Total time: %4.2f secs.\n\n\n',t);
% Total time: 55.07 secs.
fclose(fid);

另一方面,通过跳过文件按通道加载大约需要 20 倍的时间,即 20 分钟多一点:

%% load by channels (slow)
t1 = tic;
fid = fopen('rawData.dat','r');
dat = zeros(1,nSampsTotal);
for i = 1:nChan
    tic;
    fprintf('Channel %03d/%03d: loading... ');
    offset = i-1;
    fseek(fid,offset*2,'bof');
    dat = fread(fid,[1,nSampsTotal],'*int16',(nChan-1)*2);
    toc;
end
t = toc(t1); fprintf('Total time: %4.2f secs.\n\n\n',t);
% Total time: 1133.48 secs.
fclose(fid);

我还要感谢 Matlab 论坛上的 OCDER 的帮助:link

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-29
    • 1970-01-01
    • 1970-01-01
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多