Grand Central Dispatchを使用すると、いつどこで起こるかを心配することなく読み書きをスケジュールできます。以前のNSStreamベースのアプローチと比較すると、これは外部での管理が少なくて済みます。しかし、私の素朴な実装はNSStreamベースのアプローチよりも遅いです。GCDでファイルをコピーする最も効率的な方法は?
NSStreamでは、ソースと宛先の両方の優先IOサイズ(NSURLPreferredIOBlockSizeKey
)を照会しました。次に、私は全体の "優先入力サイズのチャンク"をバッファに読み込み、バッファ内の少なくとも "好ましい出力サイズ"バイトを得た時点で、すべてのチャンクを書き出しました(最後のチャンクを除いて)。これは読み込みと書き込みのパフォーマンスに関して最適に近いはずです。
しかし、GCDではこれにあまり影響しません。ソースの優先IOサイズが100kBで、ターゲットの優先IOサイズが1MBであると仮定します。私の純粋な実装では、NSStreamベースのソリューションと同じくらい頻繁に10回書くようになりました。
GCDでこれを解決する最も効率的な方法は何ですか?リーダブロックのバッファに書き込むだけで、十分なデータが収集されるとすぐに、「好ましい出力サイズ」の書き込みブロックをスケジュールしますか?私はGCDがここで私がまだ気づいていない解決策を提供するかもしれないと思います。
は、ここに私の現在のGCDソリューションの最も重要な部分です:
// input_ and output_ are of type dispatch_io_t
dispatch_io_read(
input_,
0,
SIZE_MAX,
dispatch_get_main_queue(),
^(bool done, dispatch_data_t data, int error) {
size_t data_size;
if (error) {
NSLog(@"Input: error %d", error);
[self cancel];
return;
}
if (data) {
data_size = dispatch_data_get_size(data);
if (data_size > 0) {
dispatch_io_write(
output_,
0,
data,
dispatch_get_main_queue(), ^(bool done, dispatch_data_t data, int error) {
// TODO: I don't know how to get the offset (for progress). So I need to
// pass it from the calling block.
if (error) {
NSLog(@"Output: error %d", error);
return;
}
if (done) {
bytesWritten_ += data_size;
// Update progress report here.
}
}
);
}
}
}
);
驚くばかりです。私は実装を読んで、 'dispatch_data_t'と' dispatch_data_create_concat'と 'dispatch_data_create_subrange'を使って正しい量の*コールバック*を得ることができましたが、実際には' read'/'write'コール(私は二重チェックしたい)とウォーターマークで遊んで私に良い解決策を与えるかどうかを確認する必要があります。より多くのテストをするために周回すると更新されます。 – DarkDust
大丈夫なので、 'read'と' write'のsyscallsは、期待どおりに最高水準点をそれぞれの優先IOサイズに設定すると、実際に期待されるパラメータを持っています。それで私は私の "問題"を解決することができます。低水準点を設定することは、ブロックが「短い」読み取り/書き込みのために呼び出される頻度に影響するだけで、読み取りデータを累積し、手動で書き込みするためにパーティションをスケジュールする必要があります。もちろん、問題はありません。 – DarkDust
しかし、「最適化された」バージョンは、「純粋な」実装よりも速く実行されないことが判明しました。これは、カーネルがすでにスマートであり、NSStreamとGCDのソリューションを比較すると、 。ああ。しかし、私を助けてくれてありがとう。 – DarkDust