GCD高级用法-Dispatch I/O

在读取较大文件时,如果将文件分成合适的大小并使用Global Dispatch Queue 并发读取的话,应该会比一般的读取速度快不少。现在的输入/输出硬件已经可以做到一次使用多个线程更快地并发读取了。能实现这一功能的就是Dispatch I/O 和Dispatch Data。

通过Dispatch I/O读写文件时,使用Global Dispatch Queue将1个文件按某个大小read/write。
    dispatch_async(queue, ^{ /* 读取  0     ~ 8080  字节*/ });
    dispatch_async(queue, ^{ /* 读取  8081  ~ 16383 字节*/ });
    dispatch_async(queue, ^{ /* 读取  16384 ~ 24575 字节*/ });
    dispatch_async(queue, ^{ /* 读取  24576 ~ 32767 字节*/ });
    dispatch_async(queue, ^{ /* 读取  32768 ~ 40959 字节*/ });
    dispatch_async(queue, ^{ /* 读取  40960 ~ 49191 字节*/ });
    dispatch_async(queue, ^{ /* 读取  49192 ~ 57343 字节*/ });
    dispatch_async(queue, ^{ /* 读取  57344 ~ 65535 字节*/ });

像上面这样,将文件分割为一块一块地进行读取处理。分割读取的数据通过使用Dispatch Data 可更为简单地进行结合和分割。
请看下面苹果中使用Dispatch I/O 和 Dispatch Data的例子。下面的代码摘自Apple System Log API里的源代码(地址:http://opensource.apple.com/source/Libc/Libc-763.11/gen/asl.c)
static int
_asl_auxiliary(aslmsg msg, const char *title, const char *uti, const char *url, int *out_fd)
{
    asl_msg_t *merged_msg;
    asl_msg_aux_t aux;
    asl_msg_aux_0_t aux0;
    fileport_t fileport;
    kern_return_t kstatus;
    uint32_t outlen, newurllen, len, where;
    int status, fd, fdpair[2];
    caddr_t out, newurl;
    dispatch_queue_t pipe_q;
    dispatch_io_t pipe_channel;
    dispatch_semaphore_t sem;
    /* ..... 此处省略若干代码.....*/
    
    // 创建串行队列
    pipe_q = dispatch_queue_create("PipeQ", NULL);
    // 创建 Dispatch I/O
    pipe_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, pipe_q, ^(int err){
        close(fd);
    });
    
    *out_fd = fdpair[1];
    
    // 该函数设定一次读取的大小(分割大小)
    dispatch_io_set_low_water(pipe_channel, SIZE_MAX);
    //
    dispatch_io_read(pipe_channel, 0, SIZE_MAX, pipe_q, ^(bool done, dispatch_data_t pipedata, int err){
        if (err == 0) // err等于0 说明读取无误
        {
            // 读取完“单个文件块”的大小
            size_t len = dispatch_data_get_size(pipedata);
            if (len > 0)
            {
                // 定义一个字节数组bytes
                const char *bytes = NULL;
                char *encoded;
                
                dispatch_data_t md = dispatch_data_create_map(pipedata, (const void **)&bytes, &len);
                encoded = asl_core_encode_buffer(bytes, len);
                asl_set((aslmsg)merged_msg, ASL_KEY_AUX_DATA, encoded);
                free(encoded);
                _asl_send_message(NULL, merged_msg, -1, NULL);
                asl_msg_release(merged_msg);
                dispatch_release(md);
            }
        }
        
        if (done)
        {
            dispatch_semaphore_signal(sem);
            dispatch_release(pipe_channel);
            dispatch_release(pipe_q);
        }
    });
}

说明:
dispatch_io_create 函数生成Dispatch I/O,并指定发生error时用来执行处理的block,以及执行该block的Dispatch Queue。
dispatch_io_set_low_water 函数设置一次读取的大小
dispatch_io_read 函数使用Global Dispatch Queue  开始并发读取。每当各个分割的文件块读取结束时,将含有文件块数据的 Dispatch Data(这里指pipedata) 传递给 “ dispatch_io_read 函数指定的读取结束时回调用的block ”,这个block拿到每一块读取好的 Dispatch Data(这里指pipe data),然后进行合并处理。
如果想提高文件读取速度,可以尝试使用 Dispatch I/O.


本文参考:



你可能感兴趣的:(IOS小记)