Самый эффективный способ скопировать файл с помощью GCD?

С помощью Grand Central Dispatch вы можете планировать чтение и запись, не беспокоясь о том, когда и как это произойдет. По сравнению с моим предыдущим подходом, основанным на NSStream, для этого требуется меньше внешнего управления. Однако моя наивная реализация медленнее, чем мой подход, основанный на NSStream.

Для NSStream я запросил предпочтительный размер ввода-вывода как источника, так и получателя ( NSURLPreferredIOBlockSizeKey).Затем я читал целые «предпочтительные фрагменты входного размера» в буфер, и как только у меня было хотя бы байтов «предпочтительного выходного размера» в буфере, я записывал целые фрагменты в пункт назначения (кроме последнего фрагмента, конечно). Это должно быть довольно близко к оптимальному в отношении производительности чтения и записи.

Тем не менее, с НОД я не имею большого влияния на это. Представьте, что источник имеет предпочтительный размер ввода-вывода 100 КБ, а целевой размер предпочтительного ввода-вывода для цели составляет 1 МБ: моя наивная реализация теперь будет записывать в 10 раз чаще, чем в моем решении на основе NSStream.

Итак, какой самый эффективный способ решить эту проблему с помощью НОД? Просто записать в буфер в блоке чтения, и как только будет собрано достаточно данных, запланировать блок записи «предпочтительного размера вывода»? Я предполагаю, что 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.
                        }
                    }
                );
            }
        }
    }
);
9
задан bdash 26 January 2013 в 19:51
поделиться