С Grand Central Dispatch вы можете планировать чтение и запись, не беспокоясь о том, когда и как это произойдет. По сравнению с моим предыдущим подходом, основанным на NSStream, это требует меньше управления извне. Однако моя наивная реализация медленнее, чем мой подход, основанный на NSStream.
Для NSStream я запросил предпочтительный размер ввода-вывода как источника, так и пункта назначения (NSURLPreferredIOBlockSizeKey
). Затем я полностью прочитал «предпочтительные чанки входного размера» в буфер, и как только в буфере было по крайней мере «предпочтительный выходной размер», я записал целые чанки в место назначения (за исключением, конечно, последнего чанка). Это должно быть довольно близко к оптимальному в отношении производительности чтения и записи.
Однако, с GCD, я не сильно влияю на это. Представьте, что источник имеет предпочтительный размер ввода-вывода 100 кБ и что целевой размер предпочтительного размера ввода-вывода для цели составляет 1 МБ: моя наивная реализация теперь будет писать в 10 раз чаще, чем в моем решении на основе NSStream.
Итак, как наиболее эффективно решить эту проблему с помощью 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.
}
}
);
}
}
}
);