注: この質問は、2011 年に古い MATLAB バージョン (R2009a) で観察された問題を扱っています。以下の 2016 年 7 月からの更新によると、MATLAB の問題/バグはもはや存在しないようです (R2016a でテスト済み。質問の最後までスクロールして更新を確認してください)。
私は MATLAB R2009b を使用しており、.zip ファイルのより大きなセットの内容を v7.3 mat ファイル (基礎となる HDF5 データモデルを使用) に変換する、より大きなスクリプトを作成する必要があります。読み取りOKです。問題は保存にあります。そして、実際には問題はありません。私のファイルは、 saveコマンドを使用してうまく保存されます。
私の質問はもっと意味があります: MATLAB で次の驚くべき (私にとって) 動作が見られるのはなぜですか?
一般的に私の問題を見てみましょう。この現在のテスト シナリオでは、1 つの出力 (-v7.3 mat ファイル) を生成します。この .mat ファイルには、個別の変数として40 個のブロックが含まれます。各変数には、1 から 40 までの「block_NNN」という名前が付けられ、フィールドframesおよびblockNoを持つ構造体が含まれます。フィールドフレームには、uint8 画像データの 480x240x65 シーケンスが含まれます (ここでは、 randi を使用して生成されたランダム データのみ)。フィールドblockNoにはブロック番号が含まれます。
注:実際のスクリプト (まだ完成していません) では、上記を合計 370 回実行し、合計 108 GB の生データを変換します。ということで、以下が気になります。
とにかく、最初にいくつかの一般変数を定義します。
% ダミー データとループのサイズ: num_blockCount = 40; num_blockLength = 65; num_frameHeight = 480; num_frameWidth = 240;
次に、実際の生データと同じ形状とサイズを持つダミー コードを生成します。
% 空の構造体を生成: stu_data2disk = struct(); % ブロックのループ: num_k = 1:num_blockCount の場合 % ブロック名を生成: temp_str_blockName = sprintf('block_%03u', num_k); % 現在のブロックの一時構造体を生成: temp_stu_value = struct(); temp_stu_value.frames = randi( ... [0 255]、... [num_frameHeight num_frameWidth num_blockLength], ... 「uint8」... ); temp_stu_value.blockNo = num_k; % 動的フィールド名を使用: stu_data2disk.(sprintf('block_%03u', num_k)) = temp_stu_value; 終わり
これで、すべてのランダム テスト データが struct stu_data2diskに含まれるようになりました。ここで、2 つの可能な方法のいずれかを使用してデータを保存したいと思います。
最初に簡単なものを試してみましょう:
% セーブ データ (シンプル): disp('データを簡単な方法で保存:') チック; Converted.mat -struct stu_data2disk -v7.3; を保存します。 目次;
ファイルは問題なく書き込まれます (286MB)。出力は次のとおりです。
簡単な方法でデータを保存します。 経過時間は 14.004449 秒です。
OK - それから、40 ブロックにわたって保存手順を実行したいことを思い出しました。したがって、上記の代わりに、ブロックをループして順番に追加します。
% 追加を使用してファイルに保存: disp('-append を使用してデータを保存:') チック; num_k = 1:num_blockCount の場合 % ブロック名を生成: temp_str_blockName = sprintf('block_%03u', num_k); temp_str_appendToggle = ''; もし (num_k > 1) temp_str_appendToggle = '-append'; 終わり % 生成保存コマンド: temp_str_saveCommand = [ ... '保存 '、 ... 「converted_append.mat」、... '-struct stu_data2disk', temp_str_blockName, ' '... temp_str_appendToggle、' '、... 「-v7.3」、... ';' ... ]; % 評価保存コマンド: eval(temp_str_saveCommand); 終わり 目次;
また、ファイルはうまく保存されます (286MB)。出力は次のとおりです。
-append を使用してデータを保存します。 経過時間は 0.956968 秒です。
興味深いことに、append-method ははるかに高速ですか? 私の質問はなぜですか?
からの出力dir converted*.mat
:
09-02-2011 20:38 300,236,392 変換された.mat 2011 年 9 月 2 日 20:37 300,264,316 変換された_append.mat 2 ファイル 600,500,708 バイト
ファイルのサイズが同じではありません。そして、Windows 7 でfcを使用したテストでは、多くのバイナリの違いが明らかになりました。おそらく、データが少しシフトされたので、何もわかりません。
誰かがここで何が起こっているのか知っていますか? 追加されたファイルは、おそらくより最適化されたデータ構造を使用していますか? それとも、Windows がファイルをキャッシュして、ファイルへのアクセスを大幅に高速化したのでしょうか。
2つのファイルからも試し読みをしてみました。ここに数値を提示しなければ、追加されたバージョンは少し高速でした (ただし、長期的には何かを意味する可能性があります)。
[編集] : フォーマット フラグを使用せずに試してみたところ (私のシステムではデフォルトで -v7 になっています)、あまり違いはありません:
簡単な方法でデータを保存します (-v7): 経過時間は 13.092084 秒です。 -append (-v7) を使用してデータを保存します。 経過時間は 14.345314 秒です。
[編集] : 上記の間違いを修正しました。以前、統計は -v6 のものであると述べましたが、私は間違っていました。フォーマット フラグを削除したばかりで、デフォルトが -v6 であると想定していましたが、実際には -v7 です。
Andrew の優れたフレームワークを使用して、システム上のすべての形式の新しいテスト統計を作成しました (すべての形式は、ファイルから読み取られた同じランダム テスト データ用です)。
15:15:51.422: テスト速度、フォーマット=-v6、PCWIN の R2009b、アーチ=x86、os=Microsoft Windows 7 Professional 6.1.7600 N/A ビルド 7600 15:16:00.829: 簡単な方法で保存: 0.358 秒 15:16:01.188: 複数の追加を使用して保存: 7.432 秒 15:16:08.614: 1 つの大きな追加を使用して保存: 1.161 秒 15:16:24.659: テスト速度、フォーマット=-v7、PCWIN の R2009b、アーチ=x86、os=Microsoft Windows 7 Professional 6.1.7600 N/A ビルド 7600 15:16:33.442: シンプルな方法で保存: 12.884 秒 15:16:46.329: 複数の追加を使用して保存: 14.442 秒 15:17:00.775: 1 つの大きな追加を使用して保存: 13.390 秒 15:17:31.579: テスト速度、フォーマット=-v7.3、PCWIN の R2009b、アーチ=x86、os=Microsoft Windows 7 Professional 6.1.7600 N/A ビルド 7600 15:17:40.690: シンプルな方法で保存: 13.751 秒 15:17:54.434: 複数の追加を使用して保存: 3.970 秒 15:17:58.412: 1 つの大きな追加を使用して保存: 6.138 秒
そして、ファイルのサイズ:
10-02-2011 15:16 299,528,768 変換された_format-v6.mat 10-02-2011 15:16 299,528,768 変換された_append_format-v6.mat 10-02-2011 15:16 299,528,832 変換された_append_batch_format-v6.mat 10-02-2011 15:16 299,894,027 変換された_format-v7.mat 10-02-2011 15:17 299,894,027 変換された_append_format-v7.mat 10-02-2011 15:17 299,894,075 変換された_append_batch_format-v7.mat 10-02-2011 15:17 300,236,392 変換された_format-v7.3.mat 10-02-2011 15:17 300,264,316 変換された_append_format-v7.3.mat 10-02-2011 15:18 300,101,800 変換された_append_batch_format-v7.3.mat 9 ファイル 2,698,871,005 バイト
したがって、書き込みには -v6 が最速のようです。また、ファイルサイズに大きな違いはありません。私の知る限り、HDF5 にはいくつかの基本的な inflate メソッドが組み込まれています。
うーん、おそらく基礎となる HDF5 書き込み関数の最適化ですか?
現在、基礎となるいくつかの基本的な HDF5 書き込み関数は、データセットを HDF5 ファイルに追加するために最適化されていると思います (これは、新しい変数を -7.3 ファイルに追加するときに発生します)。HDF5がまさにこの方法で最適化されるべきであるとどこかで読んだと思います...確かではありませんが。
その他の注意事項:
以下のアンドリューの回答に見られるように、動作は非常に体系的です。また、これらを関数のローカル スコープで実行するか、m-script の「グローバル」で実行するかについても非常に重要なようです。私の最初の結果は、ファイルが現在のディレクトリに書き込まれた m スクリプトからのものでした。m スクリプトで -7.3 の 1 秒の書き込みしか再現できません。関数呼び出しにより、明らかにオーバーヘッドが追加されます。
2016 年 7 月の更新:
私はこれを再び見つけ、現時点で利用可能な最新の MATLAB でテストできると考えました。Windows 7 x64 上の MATLAB R2016a では、問題が修正されたようです。
14:04:06.277: テスト速度、imax=255、R2016a on PCWIN64、arch=AMD64、16 GB、os=Microsoft Windows 7 Enterprise バージョン 6.1 (ビルド 7601: Service Pack 1) 14:04:10.600: 基本 -v7.3: 7.599 秒 5.261 GB 使用 14:04:18.229: 基本 -v7.3: 7.894 秒 5.383 GB 使用 14:04:26.154: 基本 -v7.3: 7.909 秒 5.457 GB 使用 14:04:34.096: 基本 -v7.3: 7.919 秒 5.498 GB 使用 14:04:42.048: 基本 -v7.3: 7.886 秒 5.516 GB 使用 286 MB ファイル 7.841 秒平均 14:04:50.581: multiappend -v7.3: 7.928 秒 5.819 GB 使用 14:04:58.544: multiappend -v7.3: 7.905 秒 5.834 GB 使用 14:05:06.485: multiappend -v7.3: 8.013 秒 5.844 GB 使用 14:05:14.542: multiappend -v7.3: 8.591 秒 5.860 GB 使用 14:05:23.168: multiappend -v7.3: 8.059 秒 5.868 GB 使用 286 MB ファイル 平均 8.099 秒 14:05:31.913: bigappend -v7.3: 7.727 秒 5.837 GB 使用 14:05:39.676: bigappend -v7.3: 7.740 秒 5.879 GB 使用 14:05:47.453: bigappend -v7.3: 7.645 秒 5.884 GB 使用 14:05:55.133: bigappend -v7.3: 7.656 秒 5.877 GB 使用 14:06:02.824: bigappend -v7.3: 7.963 秒 5.871 GB 使用 286 MB ファイル 平均 7.746 秒
これは、以下の受け入れられた回答の Andrew Janke のreproMatfileAppendSpeedup
関数でテストされました (形式 7.3 で 5 パス)。現在-append
は、1 回の保存が同じように、または遅くなりました。おそらく、R2009a で使用されていた HDF5 ドライバーの初期のビルドに問題があったのでしょう。