4

サイズが約 2GB (約 7000 万行) の複数のテキスト ファイルがあります。また、クアッドコア マシンを所有しており、Parallel Computing ツールボックスにアクセスできます。

通常、次のようにファイルを開いて行を読み取ることができます。

f = fopen('file.txt');
l = fgets(f);
while ~ isempty(l)
    % do something with l
    l = fgets(f);
end

「do something with」を4つのコアに分散したかったのですlが、もちろんparforループを使用する必要があります。そのためには、その場で処理するのではなく、2 GB のファイル (Perl 用語を借りるために) を MATLAB に "丸呑み" する必要があります。実際には必要ありませんl。処理の結果だけです。

並列計算でテキスト ファイルから行を読み取る方法はありますか?

編集:事前に正確な行数を見つけることができることに言及する価値があります( !wc -l mygiantfile.txt)。

EDIT2: ファイルの構造は次のとおりです。

15 1180 62444 e0e0 049c f3ec 104

つまり、3 つの 10 進数、3 つの 16 進数、および 1 つの 10 進数です。これを 7000 万行分繰り返します。

4

2 に答える 2

2

一部の matlab の組み込み関数はマルチスレッドをサポートしています。リストはこちらです。Parallel Computing ツールボックスは必要ありません。

「lで何かをする」がツールボックスの恩恵を受けることができる場合は、別の行を読む前に関数を実装してください。

または、次を使用してファイル全体を読み取ることもできます

fid = fopen('textfile.txt');
C  = textscan(fid,'%s','delimiter','\n');
fclose(fid);

次に、C のセルを並列に計算します。


parfor読み取り時間が重要な問題である場合は、ループ内でデータ ファイルの一部にアクセスすることもできます。Edric M Ellisの例を次に示します。

%Some data
x = rand(1000, 10);
fh = fopen( 'tmp.bin', 'wb' );
fwrite( fh, x, 'double' );
fclose( fh );

% Read the data
y = zeros(1000, 10);
parfor ii = 1:10
    fh = fopen( 'tmp.bin', 'rb' );
    % Get to the correct spot in the file:
    offset_bytes = (ii-1) * 1000 * 8; % 8 bytes/double
    fseek( fh, offset_bytes, 'bof' );
    % read a column
    y(:,ii) = fread( fh, 1000, 'double' );
    fclose( fh );
end

% Check
assert( isequal( x, y ) );
于 2013-09-04T17:25:45.603 に答える
2

リクエストに応じて、クラスを使用したメモリ マップトファイルの例を示します。memmapfile

データ ファイルの正確な形式が提供されていないため、独自の形式を作成します。私が作成しているデータはN、それぞれが 4 つの列で構成される行のテーブルです。

  • 最初はdoubleスカラー値です
  • 秒はsingle値です
  • uint323 番目は、 HEX 表記でa を表す固定長の文字列です(例: D091BB44)
  • 4列目はuint8値です

ランダム データを生成し、上記の構造のバイナリ ファイルに書き込むコード:

% random data
N = 10;
data = [...
    num2cell(rand(N,1)), ...
    num2cell(rand(N,1,'single')), ...
    cellstr(dec2hex(randi(intmax('uint32'), [N,1]),8)), ...
    num2cell(randi([0 255], [N,1], 'uint8')) ...
];

% write to binary file
fid = fopen('file.bin', 'wb');
for i=1:N
    fwrite(fid, data{i,1}, 'double');
    fwrite(fid, data{i,2}, 'single');
    fwrite(fid, data{i,3}, 'char');
    fwrite(fid, data{i,4}, 'uint8');
end
fclose(fid);

HEX エディタで表示した結果のファイルを次に示します。

16 進エディタで表示されたバイナリ ファイル

最初のレコードを確認できます (私のシステムはリトル エンディアンのバイト順を使用していることに注意してください)。

>> num2hex(data{1,1})
ans =
3fd4d780d56f2ca6

>> num2hex(data{1,2})
ans =
3ddd473e

>> arrayfun(@dec2hex, double(data{1,3}), 'UniformOutput',false)
ans = 
    '46'    '35'    '36'    '32'    '37'    '35'    '32'    '46'

>> dec2hex(data{1,4})
ans =
C0

次に、メモリ マッピングを使用してファイルを開きます。

m = memmapfile('file.bin', 'Offset',0, 'Repeat',Inf, 'Writable',false, ...
    'Format',{
        'double', [1 1], 'd';
        'single', [1 1], 's';
        'uint8' , [1 8], 'h';      % since it doesnt directly support char
        'uint8' , [1 1], 'i'});

これで、通常の構造体配列としてレコードにアクセスできます。

>> rec = m.Data;      % 10x1 struct array

>> rec(1)             % same as: data(1,:)
ans = 
    d: 0.3257
    s: 0.1080
    h: [70 53 54 50 55 53 50 70]
    i: 192

>> rec(4).d           % same as: data{4,1}
ans =
    0.5799

>> char(rec(10).h)    % same as: data{10,3}
ans =
2B2F493F

利点は、大きなデータ ファイルの場合、マッピングの「表示ウィンドウ」をレコードの小さなサブセットに制限し、このビューをファイルに沿って移動できることです。

% read the records two at-a-time
numRec = 10;                       % total number of records
lenRec = 8*1 + 4*1 + 1*8 + 1*1;    % length of each record in bytes
numRecPerView = 2;                 % how many records in a viewing window

m.Repeat = numRecPerView;
for i=1:(numRec/numRecPerView)
    % move the window along the file
    m.Offset = (i-1) * numRecPerView*lenRec;

    % read the two records in this window:
    %for j=1:numRecPerView, m.Data(j), end
    m.Data(1)
    m.Data(2)
end

メモリ マッピングを使用してファイルの一部にアクセスする

于 2013-09-05T16:04:05.293 に答える