美文网首页
关于GCD开发的一些事

关于GCD开发的一些事

作者: wyymaomi | 来源:发表于2017-10-26 16:01 被阅读18次

    Dispatch Queue:
    开发者将需要执行的任务添加到合适的Dispatch Queue中即可,Dispatch Queue会根据任务添加的顺序先到先执行,其中有以下几种队列:
    1.main dispatch queue
    功能跟主线程一样,通过dispatch_get_main_queue()来获取,提交到main queue的任务实际上都是在主线程执行的,所以这是一个串行队列
    2.global dispatch queues
    系统给每个应用提供四个全局的并发队列,这四个队列分别有不同的优先级:高、默认、低以及后台,用户不能去创建全局队列,只能根据优先级去获取:
    dispatch_queue_t queue;
    queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    3.user create queue
    用户可以通过dispatch_queue_create自己创建队列,该函数有两个参数,第一个是队列的名称,在debug的时候方便区分;第二个是队列的一些属性,NULL或者DISPATCH_QUEUE_SERIAL创建出来的队列事串行队列,如果传递DISPATCH_QUEUE_CONCURRENT则为并行队列。
    // 创建并行队列
    dispatch_queue_t queue;
    queue=dispatch_queue_create(“com.example.MyQueue”, DISPATCH_QUEUE_CONCURRENT);
    4.队列优先级
    dispatch_queue_create创建队列的优先级跟global dispatch queue的默认优先级一样,假如我们需要设置队列的优先级,可以通过dispatch_queue_attr_make_with_qos_class或者dispatch_set_target_queue方法;

    Quality of Service 枚举来使用user interactive,user initiated,utility和bakground
    通过这些告诉系统我们在进行什么样的工作,然后系统会通过合理的资源控制来最高效的执行任务代码,其中主要涉及到CPU调度的优先级、IO优先级、任务运行在哪个线程以及运行的顺序等等,我们通过一个抽象的Quality of Service 参数来表明任务的意图以及类别。

    一个典型的例子就是数据的读写,通常为了防止文件读写导致冲突,我们会创建一个串行的队列,所有的文件操作都是通过这个队列来执行,比如FMDB,这样就可以避免读写冲突。不过其实这样是有提升空间的,当没有更新数据时,读操作其实是可以并行进行的,而写操作需要串行执行。

    Dispatch IO
    当我们要读取一份较大文件的时候,多个线程同时去读肯定比一个线程去读的速度要快,要实现这样的功能可以通过dispatch io跟dispatch data来实现,通过dispatch io读文件时,会使用global dispatch queue将一个文件按照一个指定的分块大小同时去读区数据,类似于:
    dispatch_async(queue,^{/读取0-99字节/});
    dispatch_async(queue,^{/读取100-199字节/});
    dispatch_async(queue,^{/读取200-299字节/});
    …………
    将文件分成一块一块并行读取,读取的数据通过Dispatch Data进行结合和分割。
    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

    Dispatch Source
    Dispatch Source其实就是对kqueue功能的封装,可以去查看dispatch_source的C源码实现

    kqueue是在XNU内核中发生各种事件时,在应用程序编程方执行处理的技术,其CPU负荷非常小,尽量不占用资源。
    kqueue可以说是应用程序处理XNU内核中发生的各种事件的方法中最优秀的一种。
    Dispatch Source可处理以下事件
    DISPATCH_SOURCE_TYPE_DATA_ADD 变量增加
    DISPATCH_SOURCE_TYPE_DATA_OR 变量OR
    DISPATCH_SOURCE_TYPE_MACH_SEND MACH端口发送
    DISPATCH_SOURCE_TYPE_MACH_RECV MACH端口接收
    DISPATCH_SOURCE_TYPE_PROC 检测到与进程相关的事件
    DISPATCH_SOURCE_TYPE_READ 可读取文件映像
    DISPATCH_SOURCE_TYPE_SIGNAL 接收信号
    DISPATCH_SOURCE_TYPE_TIMER 定时器
    DISPATCH_SOURCE_TYPE_VNODE 文件系统有变更
    DISPATCH_SOURCE_TYPE_WRITE 可写入文件映像

    事件发生时,在指定的Dispatch Queue中可执行事件的处理。

    __block size_t total = 0;
    size_t size = 要读取的字节数
    char buff = (char)malloc(size);

    //设定为异步映像
    fcntl(socked,F_SETFL,O_NONBLOCK);
    //获取用于追加事件处理的Global Dispatch Queue
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAULT,0);
    // 基于READ事件做成Dispatch Source
    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socked, 0, queue);
    //指定发生READ事件时执行的处理
    dispatch_source_set_event_handle(source, ^{
    //获取可读取的字节数
    size_t available = dispatch_source_get_data(source);
    // 从映像中读取
    int length = read(socked, buff, available);
    // 发生错误时取消Dispatch Source
    if ( length < 0){
    // 错误处理
    dispatch_source_cancel(source);
    }
    total += length;
    if(total == size) {
    // buff的处理
    // 处理结束,取消Dispatch Source
    dispatch_source_cancel(source);
    }

    相关文章

      网友评论

          本文标题:关于GCD开发的一些事

          本文链接:https://www.haomeiwen.com/subject/bjekpxtx.html